1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** dglossy.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** Implementations of rpc__socket_sendmsg() (and friends) that sometimes 90** do bad things. This code should be portable since it is completely 91** layered on top of the rpc__socket_ and rpc__naf_ APIs. 92** 93** 94*/ 95 96#ifdef RPC_DG_LOSSY 97 98#include <dg.h> 99 100/* 101 * Stashed data from calls to rpc__socket_sendmsg() and rpc__socket_sendto(). 102 */ 103 104INTERNAL struct { 105 rpc_socket_t sock; 106 rpc_socket_iovec_p_t iov; 107 int iov_len; 108 rpc_addr_p_t addr; 109} sm_stash; 110 111INTERNAL int rate = 0, dbg_prnt_level = 0; 112 113typedef unsigned32 lossy_stats_t[4]; 114INTERNAL struct { 115 lossy_stats_t total; 116 lossy_stats_t recent; /* stats over last LOSSY_RECENT_INTERVAL xmits */ 117} lossy_stats; 118 119#define LOSSY_RECENT_INTERVAL 32 120 121/* =========================================================================== */ 122 123/* 124 * S E T _ L O S S Y _ P A R A M S 125 * 126 * The rate of loss is determined by the dg_lossy debug switch value. 127 * Rather than incur the expense of making the loss level completely 128 * general, we'll look specifically for the values 100, 110, 120, 130, 129 * or 140, which will indicate the percentage of packets lost/reordered. 130 * Adding 1 to any of the above values turns on the debug output. E.g. 131 * specify 130 to lose 30% of the packets, specify 131 to lose 30% of 132 * the packets AND be told about it. 133 */ 134 135INTERNAL void set_lossy_params ( void ); 136 137INTERNAL void set_lossy_params( void ) 138{ 139 if (rate != 0) 140 return; 141 142 if (RPC_DBG(rpc_es_dbg_dg_lossy, 140)) 143 { 144 rate = 5; 145 dbg_prnt_level = 141; 146 } 147 else if (RPC_DBG(rpc_es_dbg_dg_lossy, 130)) 148 { 149 rate = 6; 150 dbg_prnt_level = 131; 151 } 152 else if (RPC_DBG(rpc_es_dbg_dg_lossy, 120)) 153 { 154 rate = 10; 155 dbg_prnt_level = 121; 156 } 157 else if (RPC_DBG(rpc_es_dbg_dg_lossy, 110)) 158 { 159 rate = 20; 160 dbg_prnt_level = 111; 161 } 162 else 163 { 164 /* 165 * Anything below 10% gets set as 1%. 166 */ 167 rate = 200; 168 dbg_prnt_level = 102; 169 } 170} 171 172/* 173 * M C O P Y 174 * 175 * Make a copy of a thing into malloc'd storage. 176 */ 177 178INTERNAL unsigned8 *mcopy ( 179 unsigned8 * /*p*/, 180 int /*len*/ 181 ); 182 183INTERNAL unsigned8 *mcopy 184( 185 unsigned8 *p, 186 int len 187) 188{ 189 unsigned8 *q; 190 191 RPC_MEM_ALLOC(q, unsigned8 *, len, RPC_C_MEM_DG_LOSSY, RPC_C_MEM_NOWAIT); 192 193 /*b_c_o_p_y(p, q, len);*/ 194 195 memmove(q, p, len) ; 196 197 return (q); 198} 199 200/* 201 * M C O P Y _ I O V 202 * 203 * Make a copy of an I/O vector and all it points to into malloc'd storage. 204 */ 205 206INTERNAL rpc_socket_iovec_p_t mcopy_iov ( 207 rpc_socket_iovec_p_t /*iov*/, 208 int /*iovlen*/ 209 ); 210 211INTERNAL rpc_socket_iovec_p_t mcopy_iov 212( 213 rpc_socket_iovec_p_t iov, 214 int iovlen 215) 216{ 217 unsigned16 i; 218 rpc_socket_iovec_p_t ciov; 219 220 RPC_MEM_ALLOC(ciov, rpc_socket_iovec_p_t, sizeof(rpc_socket_iovec_t) * iovlen, 221 RPC_C_MEM_DG_LOSSY, RPC_C_MEM_NOWAIT); 222 223 for (i = 0; i < iovlen; i++) { 224 ciov[i].base = mcopy(iov[i].base, iov[i].len); 225 ciov[i].len = iov[i].len; 226 } 227 228 return (ciov); 229} 230 231/* 232 * F R E E _ I O V 233 * 234 * Free an I/O vector. 235 */ 236 237INTERNAL void free_iov ( 238 rpc_socket_iovec_p_t /*iov*/, 239 int /*iovlen*/ 240 ); 241 242INTERNAL void free_iov 243( 244 rpc_socket_iovec_p_t iov, 245 int iovlen 246) 247{ 248 unsigned16 i; 249 250 for (i = 0; i < iovlen; i++) 251 RPC_MEM_FREE(iov[i].base, RPC_C_MEM_DG_LOSSY); 252 253 RPC_MEM_FREE(iov, RPC_C_MEM_DG_LOSSY); 254} 255 256/* 257 * S T A S H _ S E N D M S G _ P K T 258 * 259 * Make a copy and stash a packet described by rpc__socket_sendmsg() args. 260 */ 261 262INTERNAL void stash_sendmsg_pkt ( 263 rpc_socket_t /*sock*/, 264 rpc_socket_iovec_p_t /*iov*/, 265 int /*iov_len*/, 266 rpc_addr_p_t /*addr*/ 267 ); 268 269INTERNAL void stash_sendmsg_pkt 270( 271 rpc_socket_t sock, 272 rpc_socket_iovec_p_t iov, 273 int iov_len, 274 rpc_addr_p_t addr 275) 276{ 277 unsigned32 st; 278 279 if (sm_stash.addr != NULL) { 280 rpc__naf_addr_free(&sm_stash.addr, &st); 281 free_iov(sm_stash.iov, sm_stash.iov_len); 282 } 283 284 sm_stash.sock = sock; 285 sm_stash.iov = mcopy_iov(iov, iov_len); 286 sm_stash.iov_len = iov_len; 287 rpc__naf_addr_copy(addr, &sm_stash.addr, &st); 288} 289 290/* 291 * X M I T _ S T A S H E D _ S E N D M S G _ P K T 292 * 293 * Transmit the packet we stashed away earlier. 294 */ 295 296INTERNAL void xmit_stashed_sendmsg_pkt (void); 297 298INTERNAL void xmit_stashed_sendmsg_pkt( void ) 299{ 300 int cc; 301 rpc_socket_error_t serr; 302 303 if (sm_stash.addr == NULL) 304 return; 305 306 RPC_DBG_PRINTF(rpc_e_dbg_general, dbg_prnt_level, 307 ("(xmit_stashed_sendmsg_pkt) Re-xmit\n")); 308 309 serr = rpc__socket_sendmsg(sm_stash.sock, sm_stash.iov, sm_stash.iov_len, 310 sm_stash.addr, &cc); 311 if (! RPC_SOCKET_IS_ERR(serr)) 312 { 313 RPC_DG_PLOG_LOSSY_SENDMSG_PKT(sm_stash.iov, sm_stash.iov_len, 2); 314 } 315} 316 317/* =========================================================================== */ 318 319/* 320 * R P C _ _ D G _ L O S S Y _ S O C K E T _ S E N D M S G 321 * 322 * Version of rpc__socket_sendmsg() that sometimes loses, duplicates, 323 * or re-orders delivery of packets. The rate of loss is determined 324 * by the dg_lossy debug switch value (see set_lossy_params()). 325 */ 326 327PRIVATE rpc_socket_error_t rpc__dg_lossy_socket_sendmsg 328( 329 rpc_socket_t sock, 330 rpc_socket_iovec_p_t iov, /* array of bufs of data to send */ 331 int iov_len, /* number of bufs */ 332 rpc_addr_p_t addr, /* addr of receiver */ 333 int *cc /* returned number of bytes actually sent */ 334) 335{ 336 int i; 337 rpc_socket_error_t serr; 338 339 /* 340 * Iff the lossy switch has been set... 341 */ 342 343 if (RPC_DBG(rpc_es_dbg_dg_lossy, 100)) 344 { 345 set_lossy_params(); 346 if (lossy_stats.total[3] % LOSSY_RECENT_INTERVAL == 0) 347 { 348 lossy_stats.recent[0] = lossy_stats.recent[1] = 349 lossy_stats.recent[2] = lossy_stats.recent[3] = 0; 350 } 351 lossy_stats.recent[3]++; 352 lossy_stats.total[3]++; 353 switch ((int) RPC_RANDOM_GET(0, 10000) % rate) /* Min/Max values arbitrarily set */ 354 { 355 case 0: /* Drop the pkt on the floor */ 356 RPC_DBG_PRINTF(rpc_e_dbg_general, dbg_prnt_level, 357 ("(rpc__dg_lossy_socket_sendmsg) Drop pkt\n")); 358 lossy_stats.recent[0]++; 359 lossy_stats.total[0]++; 360 *cc = 0; 361 for (i = 0; i < iov_len; i++) 362 *cc += iov[i].len; 363 RPC_DG_PLOG_LOSSY_SENDMSG_PKT(iov, iov_len, 0); 364 return (RPC_C_SOCKET_OK); 365 case 1: /* Stash the pkt away for later re-xmit */ 366 RPC_DBG_PRINTF(rpc_e_dbg_general, dbg_prnt_level, 367 ("(rpc__dg_lossy_socket_sendmsg) Stash pkt\n")); 368 lossy_stats.recent[1]++; 369 lossy_stats.total[1]++; 370 stash_sendmsg_pkt(sock, iov, iov_len, addr); 371 break; 372 case 2: /* Re-xmit sendto stashed pkt if we have one */ 373 lossy_stats.recent[2]++; 374 lossy_stats.total[2]++; 375 xmit_stashed_sendmsg_pkt(); 376 break; 377 } 378 } 379 380 serr = rpc__socket_sendmsg(sock, iov, iov_len, addr, cc); 381 if (! RPC_SOCKET_IS_ERR(serr)) 382 { 383 RPC_DG_PLOG_LOSSY_SENDMSG_PKT(iov, iov_len, 3); 384 } 385 return (serr); 386} 387 388#else 389/* 390 * If RPC_DG_LOSSY is not defined, declare a dummy variable to 391 * enable this module to be compiled under strict ansi c standards. 392 */ 393#ifndef __GNUC__ 394static char dummy, *_dummy_addr = &dummy; 395#endif 396#endif /* RPC_DG_LOSSY */ 397