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**      dgclsn.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  DG protocol service routines.  Client-oriented routines that run in the
90**  listener thread.
91**
92**
93*/
94
95#include <dg.h>
96#include <dgxq.h>
97#include <dgclsn.h>
98#include <dgcall.h>
99
100INTERNAL boolean32 chk_sboot (
101        rpc_dg_recvq_elt_p_t  /*rqe*/,
102        rpc_dg_ccall_p_t  /*ccall*/
103    );
104
105INTERNAL void do_quack_body (
106        rpc_dg_recvq_elt_p_t  /*rqe*/,
107        rpc_dg_ccall_p_t  /*ccall*/
108    );
109
110/* ========================================================================= */
111
112/*
113 * C H K _ S B O O T
114 *
115 * Server boot time processing / verification. Checks that a received
116 * packet is from the same instance of the server as previously received
117 * packets for this call.  This function is used in all server->client
118 * packet type managers.
119 */
120
121INTERNAL boolean32 chk_sboot
122(
123    rpc_dg_recvq_elt_p_t rqe,
124    rpc_dg_ccall_p_t ccall
125)
126{
127    if (ccall->c.call_server_boot != 0 &&
128        rqe->hdrp->server_boot != ccall->c.call_server_boot)
129    {
130        RPC_DBG_GPRINTF(("s->c Server boot time mismatch [%s]\n",
131            rpc__dg_act_seq_string(rqe->hdrp)));
132        rpc__dg_call_signal_failure(&ccall->c, rpc_s_wrong_boot_time);
133        return (false);
134    }
135    else
136    {
137        return (true);
138    }
139}
140
141/*
142 * R P C _ _ D G _ D O _ C O M M O N _ R E S P O N S E
143 *
144 * Provide processing common for receipt of response, reject, fault, and
145 * quack packets.
146 *
147 * Returns:   false - if the packet should be discarded (old or a duplicate).
148 *            true  - otherwise
149 *
150 */
151
152PRIVATE boolean rpc__dg_do_common_response
153(
154    rpc_dg_sock_pool_elt_p_t sp,
155    rpc_dg_recvq_elt_p_t rqe,
156    rpc_dg_ccall_p_t ccall
157)
158{
159    rpc_dg_pkt_hdr_p_t hdrp = rqe->hdrp;
160    rpc_dg_ptype_t ptype = RPC_DG_HDR_INQ_PTYPE(hdrp);
161    unsigned32 st;
162
163    /*
164     * Make sure the packet is for the current call.  Note: the sequence
165     * number may be greater than our current one due to proxy calls.
166     *
167     * Response packet considerations:
168     * If we're in a call and this response is for an old call, send
169     * an "ack" just in case the activity ID has been reused on a call
170     * to a different server.  If the response is to a previous call
171     * then assume that an "ack" was lost and resend it.  (Note that
172     * we will only resend an ACK on receipt of the last, or only, fragment
173     * of a response;  we do this because when an ACK is lost, the server
174     * will retransmit the last blast's worth of data and we don't want
175     * to send ACKs for each one.)  Duplicate "ack"s are not a problem
176     * because servers will simply ignore them. Note that the seq number
177     * can actually be greater than the current call's sequence due to
178     * proxy calls.
179     *
180     * Fault packet considerations:
181     * If the fault is to a previous call it may be a duplicate, however,
182     * it may also be a valid fault packet that has not been "ack"ed.
183     * Valid fault packets may result from activity ID's being rapidly
184     * reused after an "ack" has been lost.  Also, the packet may be
185     * for this call and we may already be in an error state which may
186     * have been because we've already received a fault but for some
187     * reason we haven't completed the call yet.  The proper action in
188     * all three of the above cases is to send an "ack" to stop the server
189     * from resending the fault.  Any extra "ack"s will be ignored by
190     * the server.  Note that the seq number can actually be greater
191     * than the current call's sequence due to proxy calls.
192     */
193
194    if (ccall == NULL
195        || RPC_DG_SEQ_IS_LT(hdrp->seq, ccall->c.call_seq)
196        || (ptype == RPC_C_DG_PT_FAULT && ccall->fault_rqe != NULL)
197        || (ptype == RPC_C_DG_PT_WORKING && ccall->c.state != rpc_e_dg_cs_recv))
198    {
199        if (ptype == RPC_C_DG_PT_FAULT ||
200            (ptype == RPC_C_DG_PT_RESPONSE &&
201             (! RPC_DG_HDR_FLAG_IS_SET(hdrp, RPC_C_DG_PF_FRAG) ||
202              RPC_DG_HDR_FLAG_IS_SET(hdrp, RPC_C_DG_PF_LAST_FRAG))))
203        {
204            rpc__dg_xmit_hdr_only_pkt(sp->sock, (rpc_addr_p_t) &rqe->from,
205                rqe->hdrp, RPC_C_DG_PT_ACK);
206        }
207        RPC_DBG_PRINTF(rpc_e_dbg_recv, 1,
208                ("(rpc__dg_do_common_response) Dropped %s [%s]\n",
209                rpc__dg_pkt_name(ptype), rpc__dg_act_seq_string(rqe->hdrp)));
210        return (false);
211    }
212
213    RPC_DG_CALL_LOCK_ASSERT(&ccall->c);
214
215    /*
216     * If the call has been orphaned, our interest in various pkt types
217     * is lessened.
218     */
219
220    if (ccall->c.state == rpc_e_dg_cs_orphan
221            && (ptype == RPC_C_DG_PT_RESPONSE || ptype == RPC_C_DG_PT_FACK))
222    {
223        RPC_DBG_PRINTF(rpc_e_dbg_general, 4,
224        ("(rpc__dg_do_common_response) Call failed or orphaned, Dropped %s [%s]\n",
225            rpc__dg_pkt_name(ptype), rpc__dg_act_seq_string(rqe->hdrp)));
226        return (false);
227    }
228
229    /*
230     * If all the packets has been received for this call, we don't have to
231     * do any more work here (in particular, we don't want to check the boot
232     * time since in the case of broadcast, we don't want to get upset by
233     * responses from other servers which will of course have different
234     * boot times).
235     */
236
237    if (ccall->c.rq.all_pkts_recvd)
238        return (false);
239
240    if (! chk_sboot(rqe, ccall))
241    {
242        return (false);
243    }
244
245    /*
246     * There are several interesting and / or necessary pieces of
247     * information that we need to snag from a response packet header.
248     * Pick up the hints and the response sequence number (to properly
249     * manage our sequence number space in the presence of proxy calls).
250     *
251     * Now that we've successfully "(re)connected" to the server we also
252     * reset the call's com_timeout_knob to be no lower than the default
253     * timeout level.
254     */
255
256    if (! ccall->response_info_updated)
257    {
258        ccall->response_info_updated = true;
259        ccall->c.call_ahint = hdrp->ahint;
260        ccall->c.call_ihint = hdrp->ihint;
261
262        ccall->c.com_timeout_knob = MAX(ccall->c.com_timeout_knob,
263                                        rpc_c_binding_default_timeout);
264    }
265
266    /*
267     * We need to pick update the high_seq (highest proxy call seq) info
268     * from the response stream.  Logically, we only need to get this
269     * info for the last pkt of the response stream, however, it's
270     * easier to always pick it up and just make certain that we
271     * don't allow it to go backwards (without this check it can
272     * go backwards, trust me).
273     */
274
275    if (RPC_DG_SEQ_IS_LT(ccall->c.high_seq,hdrp->seq))
276        ccall->c.high_seq = hdrp->seq;
277
278    /*
279     * Update our server address binding if necessary.  Also,
280     * if we're are updating the remote address being used for
281     * this conversation, we must also call the NAF routine to
282     * to determine the max_path_tpdu for this path.
283     */
284
285    if (! ccall->server_bound)
286    {
287        ccall->server_bound = true;
288        ccall->c.call_server_boot = hdrp->server_boot;
289        rpc__naf_addr_overcopy((rpc_addr_p_t) &rqe->from, &ccall->c.addr, &st);
290
291        if ((ccall->c.xq.base_flags & RPC_C_DG_PF_BROADCAST) != 0)
292        {
293            RPC_DG_CALL_SET_MAX_FRAG_SIZE(&ccall->c, &st);
294
295            RPC_DG_RBUF_SIZE_TO_WINDOW_SIZE(sp->rcvbuf,
296                                            sp->is_private,
297                                            ccall->c.xq.max_frag_size,
298                                            ccall->c.rq.window_size);
299            RPC_DBG_PRINTF(rpc_e_dbg_recv, 7,
300          ("(rpc__dg_do_common_response) Set ws %d, rcvbuf %u, max fs %u\n",
301              ccall->c.rq.window_size, sp->rcvbuf, ccall->c.xq.max_frag_size));
302        }
303    }
304
305    /*
306     * Update the call's had_pending state with the information in the response.
307     * This is really only necesssary on the last pkt of a response, but it's
308     * probably cheaper to always do it.  Ensure that once a "had_pending"
309     * state is detected, it stays that way.
310     */
311
312    if (RPC_DG_HDR_FLAG2_IS_SET(hdrp, RPC_C_DG_PF2_CANCEL_PENDING))
313    {
314        if (!ccall->cancel.server_had_pending)
315        {
316            RPC_DBG_PRINTF(rpc_e_dbg_cancel, 10,
317                ("(rpc__dg_do_common_response) setting cancel_pending\n"));
318        }
319        ccall->cancel.server_had_pending = true;
320    }
321
322    return (true);
323}
324
325/*
326 * R P C _ _ D G _ D O _ R E J E C T
327 *
328 * Handle a call reject packet
329 *
330 * Signal a call failure with the appropriate status.
331 */
332
333PRIVATE boolean rpc__dg_do_reject
334(
335    rpc_dg_sock_pool_elt_p_t sp,
336    rpc_dg_recvq_elt_p_t rqe,
337    rpc_dg_ccall_p_t ccall
338)
339{
340    unsigned32 mst;
341
342    /*
343     * Perform common response packet processing.
344     */
345
346    if (! rpc__dg_do_common_response(sp, rqe, ccall))
347        return (RPC_C_DG_RDF_FREE_RQE);
348
349    RPC_DBG_GPRINTF(("(rpc__dg_do_reject) Got a live one [%s]\n",
350        rpc__dg_act_seq_string(rqe->hdrp)));
351
352    RPC_DG_CALL_LOCK_ASSERT(&ccall->c);
353
354    /*
355     * When in the orphan state, a reject is just as good as a quack.
356     */
357
358    if (ccall->c.state == rpc_e_dg_cs_orphan)
359    {
360        ccall->quit.quack_rcvd = true;
361        rpc__dg_call_signal(&ccall->c);
362        return (RPC_C_DG_RDF_FREE_RQE);
363    }
364
365    /*
366     * Free any packets we have on the transmit queue still since the
367     * fault is (implicitly) ack'ing them.
368     */
369
370    if (ccall->c.xq.head != NULL)
371        rpc__dg_xmitq_free(&ccall->c.xq, &ccall->c);
372
373    /*
374     * A reject response terminates the OUTs data stream.
375     */
376
377    ccall->c.rq.all_pkts_recvd = true;
378
379    /*
380     * Get the NCA status from the reject packet body and map it to a local
381     * status code.  Blow off the call with this mapped status.
382     */
383
384    rpc__dg_get_epkt_body_st(rqe, &ccall->reject_status);
385
386    switch ((int)ccall->reject_status)
387    {
388        case nca_s_comm_failure:        mst = rpc_s_comm_failure;        break;
389        case nca_s_unk_if:              mst = rpc_s_unknown_if;          break;
390        case nca_s_unsupported_type:    mst = rpc_s_unsupported_type;    break;
391        case nca_s_manager_not_entered: mst = rpc_s_manager_not_entered; break;
392        case nca_s_op_rng_error:        mst = rpc_s_op_rng_error;        break;
393        case nca_s_who_are_you_failed:  mst = rpc_s_who_are_you_failed;  break;
394        case nca_s_proto_error:         mst = rpc_s_protocol_error;      break;
395        case nca_s_wrong_boot_time:     mst = rpc_s_wrong_boot_time;     break;
396        default:                        mst = rpc_s_unknown_reject;      break;
397    }
398
399    rpc__dg_call_signal_failure(&ccall->c, mst);
400
401    return (RPC_C_DG_RDF_FREE_RQE);
402}
403
404/*
405 * R P C _ _ D G _ D O _ F A U L T
406 *
407 * Handle a call fault packet.
408 *
409 * Stash the fault pkt away for eventual retrieval by the client
410 * stub and signal a call "call_faulted" failure.
411 */
412
413PRIVATE boolean rpc__dg_do_fault
414(
415    rpc_dg_sock_pool_elt_p_t sp,
416    rpc_dg_recvq_elt_p_t rqe,
417    rpc_dg_ccall_p_t ccall
418)
419{
420
421    /*
422     * Perform common response packet processing.
423     */
424
425    if (! rpc__dg_do_common_response(sp, rqe, ccall))
426        return (RPC_C_DG_RDF_FREE_RQE);
427
428    RPC_DBG_GPRINTF(("(rpc__dg_do_fault) Got a live one [%s]\n",
429        rpc__dg_act_seq_string(rqe->hdrp)));
430
431    RPC_DG_CALL_LOCK_ASSERT(&ccall->c);
432
433    /*
434     * When in the orphan state, a fault is just as good as a quack.
435     */
436
437    if (ccall->c.state == rpc_e_dg_cs_orphan)
438    {
439        ccall->quit.quack_rcvd = true;
440        rpc__dg_call_signal(&ccall->c);
441        return (RPC_C_DG_RDF_FREE_RQE);
442    }
443
444    /*
445     * A fault response terminates the OUTs data stream.
446     */
447
448    ccall->c.rq.all_pkts_recvd = true;
449
450    ccall->fault_rqe = rqe;
451    rpc__dg_call_signal_failure(&ccall->c, rpc_s_call_faulted);
452
453    return (0 /* DON'T free the rqe */);
454}
455
456/*
457 * R P C _ _ D G _ D O _ R E S P O N S E
458 *
459 * Handle a response packet.
460 */
461
462PRIVATE boolean rpc__dg_do_response
463(
464    rpc_dg_sock_pool_elt_p_t sp,
465    rpc_dg_recvq_elt_p_t rqe,
466    rpc_dg_ccall_p_t ccall
467)
468{
469    boolean rqe_wake_thread;
470    rpc_dg_xmitq_p_t xq;
471    boolean32 drop;
472
473    /*
474     * Perform common response packet processing.
475     */
476
477    if (! rpc__dg_do_common_response(sp, rqe, ccall))
478        return (RPC_C_DG_RDF_FREE_RQE);
479
480    RPC_DG_CALL_LOCK_ASSERT(&ccall->c);
481
482    xq = &ccall->c.xq;
483
484    /*
485     * Free any packets we have on the transmit queue still since the
486     * response is (implicitly) ack'ing them.
487     */
488
489    if (xq->head != NULL)
490        rpc__dg_xmitq_free(xq, &ccall->c);
491
492    /*
493     * If we were pinging the server, we can stop now.
494     */
495
496    RPC_DG_PING_INFO_INIT(&ccall->ping);
497
498    /*
499     * Add the packet to the receive queue, noting whether or not it
500     * actually gets queued.
501     */
502
503    drop = ! rpc__dg_call_recvq_insert(&ccall->c, rqe, &rqe_wake_thread);
504
505    /*
506     * If "recvq_insert" told us that there are a sufficient number of
507     * rqe's to warrant wakeing up the client then do so.
508     */
509
510    if (rqe_wake_thread)
511    {
512        rpc__dg_call_signal(&ccall->c);
513    }
514
515    /*
516     * Decide on a return status.  If the packet was dropped, tell the
517     * caller to free the packet.  Otherwise, if we signalled the call
518     * that the packet was queued to, tell the listener thread to yield.
519     * Otherwise, return 0, meaning, don't free the packet, or yield.
520     */
521
522    if (drop)
523        return (RPC_C_DG_RDF_FREE_RQE);
524
525    if (rqe_wake_thread)
526        return (RPC_C_DG_RDF_YIELD /* and DON'T free the rqe */);
527
528    return (0 /* DON'T free the rqe */);
529}
530
531/*
532 * P I N G _ L A T E R
533 *
534 * Schedule a ping to happen later for the specified ccall.  This routine is
535 * shared by the "working" and "nocall/fack" packet processing routines.
536 */
537
538INTERNAL void ping_later (
539        rpc_dg_ccall_p_t /*ccall*/,
540        rpc_dg_recvq_elt_p_t /*rqe*/
541    );
542
543INTERNAL void ping_later
544(
545    rpc_dg_ccall_p_t ccall,
546    rpc_dg_recvq_elt_p_t rqe ATTRIBUTE_UNUSED
547)
548{
549    struct rpc_dg_ping_info_t *ping;
550    rpc_clock_t now, duration, interval;
551
552    ping = &ccall->ping;
553    now = rpc__clock_stamp();
554
555    /*
556     * Stop any ongoing pinging.
557     */
558
559    ping->pinging = false;
560
561    /*
562     * Compute the time to start pinging again as a function of how long
563     * the call has been running.  (The longer the call's been running,
564     * the longer we wait until starting to ping again.)
565     *
566     * Note that there's an interaction between the ping rate and the
567     * server's "max receive state idle time":  the server, while in
568     * the receive state, may declare the client dead if it doesn't hear
569     * from it from it in a while.
570     */
571
572    duration = now - ccall->c.start_time;
573
574    if (duration < RPC_CLOCK_SEC(10))
575        interval = RPC_CLOCK_SEC(3);
576    else if (duration < RPC_CLOCK_SEC(30))
577        interval = RPC_CLOCK_SEC(10);
578    else
579        interval = RPC_CLOCK_SEC(30);
580
581    ping->next_time = now + interval;
582
583    RPC_DBG_PRINTF(rpc_e_dbg_general, 3,
584        ("(stop_pinging) Next ping at: now = %lu, interval = %lu [%s]\n",
585        (unsigned long)now, (unsigned long)interval,
586	rpc__dg_act_seq_string(rqe->hdrp)));
587}
588
589/*
590 * R P C _ _ D G _ D O _ W O R K I N G
591 *
592 * Handle a working packet.  Working's are received in response to pings
593 * and mean that the server has received all the in's.  Note that the
594 * server may still fail the call (e.g., because it doesn't handle the
595 * requested interface).
596 */
597
598PRIVATE boolean rpc__dg_do_working
599(
600    rpc_dg_sock_pool_elt_p_t sp,
601    rpc_dg_recvq_elt_p_t rqe,
602    rpc_dg_ccall_p_t ccall
603)
604{
605    rpc_dg_xmitq_p_t xq;
606
607    RPC_LOCK_ASSERT(0);
608
609    /*
610     * Perform common response packet processing.
611     */
612
613    if (! rpc__dg_do_common_response(sp, rqe, ccall))
614        return (RPC_C_DG_RDF_FREE_RQE);
615
616    RPC_DG_CALL_LOCK_ASSERT(&ccall->c);
617
618    xq = &ccall->c.xq;
619
620    /*
621     * If our call is non-idempotent, free any packets we have on the
622     * transmit queue still since the working response is (implicitly)
623     * ack'ing the receipt of them.  Note well that we MUST NOT free
624     * the queue for idempotent calls since the server is allowed to
625     * drop the response in which case a subsequent ping from us will
626     * induce a nocall response and oblige us to retransmit the request.
627     */
628
629    if ((xq->base_flags & RPC_C_DG_PF_IDEMPOTENT) == 0 &&
630        xq->head != NULL)
631    {
632        rpc__dg_xmitq_free(xq, &ccall->c);
633    }
634
635    ping_later(ccall, rqe);
636
637    return (RPC_C_DG_RDF_FREE_RQE);
638}
639
640/*
641 * R P C _ _ D G _ D O _ N O C A L L
642 *
643 * Handle a no-call packet.  No-call's are received in response to pings.
644 * Note that in the case of large in's, some of which have already been
645 * fack'd, no-call simply means that not all the in's have arrived, NOT
646 * that the server knows nothing about the call.  Confusing, eh?
647 */
648
649PRIVATE boolean rpc__dg_do_nocall
650(
651    rpc_dg_sock_pool_elt_p_t sp,
652    rpc_dg_recvq_elt_p_t rqe,
653    rpc_dg_ccall_p_t ccall
654)
655{
656    rpc_dg_xmitq_p_t xq;
657
658    RPC_LOCK_ASSERT(0);
659
660    /*
661     * Make sure the pkt is for the current call, that we are in the
662     * receive state, and that the call has not already failed.  Note:
663     * the sequence number may be greater than our current one due to
664     * proxy calls.
665     */
666
667    if (ccall == NULL
668        || RPC_DG_SEQ_IS_LT(rqe->hdrp->seq, ccall->c.call_seq)
669        || ccall->c.state != rpc_e_dg_cs_recv
670        || ccall->c.status != rpc_s_ok)
671    {
672        RPC_DBG_PRINTF(rpc_e_dbg_general, 2,
673            ("(rpc__dg_do_nocall) Dropped [%s]\n",
674            rpc__dg_act_seq_string(rqe->hdrp)));
675        return (RPC_C_DG_RDF_FREE_RQE);
676    }
677
678    RPC_DG_CALL_LOCK_ASSERT(&ccall->c);
679
680    if (! chk_sboot(rqe, ccall))
681    {
682        return (RPC_C_DG_RDF_FREE_RQE);
683    }
684
685    xq = &ccall->c.xq;
686
687    /*
688     * When in the orphan state, a nocall is just as good as a quack.
689     */
690
691    if (ccall->c.state == rpc_e_dg_cs_orphan)
692    {
693        ccall->quit.quack_rcvd = true;
694        rpc__dg_call_signal(&ccall->c);
695        return (RPC_C_DG_RDF_FREE_RQE);
696    }
697
698    if (xq->head == NULL) {
699        RPC_DBG_PRINTF(rpc_e_dbg_general, 2,
700            ("(rpc__dg_do_nocall) Transmit queue is empty [%s]\n",
701            rpc__dg_act_seq_string(rqe->hdrp)));
702        return (RPC_C_DG_RDF_FREE_RQE);
703    }
704
705    /*
706     * No-call means we should stop pinging.
707     */
708
709    RPC_DG_PING_INFO_INIT(&ccall->ping);
710
711    /*
712     * If there's a body in this no-call, it must be a fack body.
713     */
714
715    if (rqe->hdrp->len > 0)
716    {
717        boolean sent_data;
718
719        /*
720         * Process the nocall just like a fack.
721         */
722
723        RPC_DBG_PRINTF(rpc_e_dbg_general, 3,
724            ("(rpc__dg_do_nocall) Has fack body [%s]\n",
725            rpc__dg_act_seq_string(rqe->hdrp)));
726
727        rpc__dg_fack_common(sp, rqe, &ccall->c, &sent_data);
728
729        /*
730         * Conditionally schedule the next ping for later (i.e., backed
731         * off, just as if we'd gotten a "working".  The "condition"
732         * is that the fack processing has NOT just queued up some data
733         * to send.  In this case, we must ping soon to verify that the
734         * frag was received.  (The problem case comes when the call
735         * has been queued for long enough that the ping interval is
736         * longer than the comm timeout setting.)
737         */
738
739        if (! sent_data)
740        {
741            ping_later(ccall, rqe);
742        }
743
744        return (RPC_C_DG_RDF_FREE_RQE);
745    }
746
747    /*
748     * =========== Process a no-call that lacks a fack body ===========
749     */
750
751    /*
752     * If this is an idempotent call (which must mean a single pkt
753     * request, though we won't count on that) and we're retransmitting
754     * the beginning of a call, then it may have been the case that the
755     * call actually ran, but the response was lost.  To ensure that
756     * we don't loose a cancel, reset some of our cancel state (which may
757     * result in re-forwarding a cancel) so that call_end() can make an
758     * accurate cancel_pending decision.
759     */
760
761    if (xq->head->fragnum == 0
762        && (ccall->c.xq.base_flags & RPC_C_DG_PF_IDEMPOTENT))
763    {
764        ccall->cancel.server_count = 0;
765        ccall->cancel.server_is_accepting = true;
766        ccall->cancel.server_had_pending = false;
767        /* Retain *current* ccall->cancel.local_count */
768    }
769
770    /*
771     * Since we had begun pinging, we know that everything on the queue
772     * has been sent atleast once.  However, the receipt of a nocall
773     * is an indication from the server that it's missing something.
774     * Unfortunately, we have no way of telling what it's missing, so
775     * all we can do is begin sending everything on the queue again.
776     */
777
778    rpc__dg_xmitq_restart(&ccall->c);
779
780    RPC_DBG_PRINTF(rpc_e_dbg_general, 3,
781        ("(rpc__dg_do_nocall) Retransmitting %d frags [%s]\n",
782        xq->blast_size, rpc__dg_act_seq_string(rqe->hdrp)));
783
784    return (RPC_C_DG_RDF_FREE_RQE);
785}
786
787/*
788 * D O _ Q U A C K _ B O D Y
789 *
790 * Process the contents of a quack body.
791 * A quack with a body is interpreted as a cancel-request ack.
792 */
793
794INTERNAL void do_quack_body
795(
796    rpc_dg_recvq_elt_p_t rqe,
797    rpc_dg_ccall_p_t ccall
798)
799{
800    unsigned32 cancel_id;
801    boolean server_is_accepting;
802
803#ifndef MISPACKED_HDR
804
805    rpc_dg_quackpkt_body_p_t bodyp = (rpc_dg_quackpkt_body_p_t) &rqe->pkt->body;
806
807    /*
808     * Make sure we understand the quack packet body version.
809     */
810
811    if (bodyp->vers != RPC_C_DG_QUACKPKT_BODY_VERS)
812    {
813        RPC_DBG_GPRINTF(("(do_quack_body) Unknown version; Dropped [%s]\n",
814                rpc__dg_act_seq_string(rqe->hdrp)));
815        return;
816    }
817
818    /*
819     * Extract the cancel_id of the cancel being ack'ed and the sender's
820     * server_is_accepting (cancels) flag.
821     */
822
823    cancel_id           = bodyp->cancel_id;
824    server_is_accepting = bodyp->server_is_accepting;
825
826    if (NDR_DREP_INT_REP(rqe->hdrp->drep) != ndr_g_local_drep.int_rep)
827    {
828        SWAB_INPLACE_32(cancel_id);
829    }
830#else
831
832#error "No code for mispacked_hdr here!"
833
834#endif /* MISPACKED_HDR */
835
836    /*
837     * Update the call handle information.  Since pkts may be duplicated
838     * / rcvd out of order... ignore "old" cancel quacks.
839     *
840     * While we currently don't think that a server will ever tell us
841     * to re-enable acceptance once it declares that it is no longer
842     * accepting cancels there's no good reason to enforce this (and
843     * there's good reason to leave the flexibility in).  Of course,
844     * we don't want "old" acks to affect the state.
845     *
846     * Define the architectural requirement that servers may adjust their
847     * cancel acceptance state as they see fit; however, the clients
848     * will not adapt to the new state unless the state is conveyed to
849     * the client in a cancel quack specifying a cancel_id that
850     * at least as high as the highest cancel previously acked by the
851     * server.
852     */
853    if (cancel_id < ccall->cancel.server_count)
854    {
855        RPC_DBG_PRINTF(rpc_e_dbg_recv, 1,
856                ("(do_quack_body) Old quack; Dropped [%s]\n",
857                rpc__dg_act_seq_string(rqe->hdrp)));
858        return;
859    }
860
861    ccall->cancel.server_count          = cancel_id;
862    ccall->cancel.server_is_accepting   = server_is_accepting;
863}
864
865/*
866 * R P C _ _ D G _ D O _ Q U A C K
867 *
868 * Handle a call quit acknowlegement packet.
869 * Quacks have two forms:
870 *  a)  orphan-request ack (2.0 and pre 2.0)
871 *  b)  cancel-request ack (2.0 only)
872 *
873 * Note: A 2.0 client sending a cancel-request will get a orphan-request-ack
874 * when talking to a 1.5.1 server (since cancel and orphan requests are
875 * identical from the 1.5.1 server's perspective).
876 */
877
878PRIVATE boolean rpc__dg_do_quack
879(
880    rpc_dg_sock_pool_elt_p_t sp,
881    rpc_dg_recvq_elt_p_t rqe,
882    rpc_dg_ccall_p_t ccall
883)
884{
885    /*
886     * Perform common response packet processing.
887     */
888
889    if (! rpc__dg_do_common_response(sp, rqe, ccall))
890        return (RPC_C_DG_RDF_FREE_RQE);
891
892    RPC_DBG_PRINTF(rpc_e_dbg_general, 3,
893        ("(rpc__dg_do_quack) Rcvd %s quack [%s]\n",
894        rqe->hdrp->len != 0 ? "cancel" : "orphan",
895        rpc__dg_act_seq_string(rqe->hdrp)));
896
897    RPC_DG_CALL_LOCK_ASSERT(&ccall->c);
898
899    /*
900     * An orphan-quack is identified by a quack without a body
901     * (a cancel-quack has a body).
902     */
903    if (rqe->hdrp->len != 0)
904    {
905	do_quack_body(rqe, ccall);
906    }
907    else
908    {
909        /*
910         * If we're not in the orphan state (this orphan-quack IS for our call)
911         * we must be talking to a 1.5.1 server (which has now orphaned
912         * the call, so there's no need to continue).
913         */
914
915        if (ccall->c.state != rpc_e_dg_cs_orphan)
916        {
917            RPC_DBG_GPRINTF(
918                ("(rpc__dg_do_quack) Rcvd orphan quack in response to cancel %s [%s]\n",
919                rpc__dg_call_state_name(ccall->c.state),
920                rpc__dg_act_seq_string(rqe->hdrp)));
921            rpc__dg_call_signal_failure(&ccall->c, rpc_s_call_cancelled);
922            return (RPC_C_DG_RDF_FREE_RQE);
923        }
924
925        /*
926         * A "quack" packet has been received, signal the thread waiting in
927         * rpc__dg_call_end() to clean up the resources held by the call and
928         * transition to the idle state.
929         */
930
931        ccall->quit.quack_rcvd = true;
932        rpc__dg_call_signal(&ccall->c);
933    }
934
935    return (RPC_C_DG_RDF_FREE_RQE);
936}
937