#include <commonp.h>
#include <com.h>
#include <ndrp.h>
#include <cnp.h>
#include <cnnet.h>
#include <cnsm.h>
#include <cnassm.h>
#include <cnclsm.h>
#include <cnpkt.h>
#include <cnfbuf.h>
#include <cnassoc.h>
#include <cnrcvr.h>
#include <comauth.h>
#include <cncall.h>
#include <comcthd.h>
#include <cncthd.h>
typedef struct
{
unsigned8 class;
unsigned8 event;
} rpc_cn_pkt_info_t, *rpc_cn_pkt_info_p_t;
#define CALL_CLASS_PKT 0
#define ASSOC_CLASS_PKT 1
#define DGRAM_CLASS_PKT 2
#ifndef RPC_C_DGRAM_TYPE_PKT
#define RPC_C_DGRAM_TYPE_PKT 0xff
#endif
INTERNAL rpc_cn_pkt_info_t packet_info_table[] =
{
{ CALL_CLASS_PKT, RPC_C_CALL_RPC_IND },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ CALL_CLASS_PKT, RPC_C_CALL_RPC_CONF },
{ CALL_CLASS_PKT, RPC_C_CALL_FAULT },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },
{ ASSOC_CLASS_PKT, RPC_C_ASSOC_IND },
{ ASSOC_CLASS_PKT, RPC_C_ASSOC_ACCEPT_CONF },
{ ASSOC_CLASS_PKT, RPC_C_ASSOC_REJECT_CONF },
{ ASSOC_CLASS_PKT, RPC_C_ASSOC_ALTER_CONTEXT_IND },
{ ASSOC_CLASS_PKT, RPC_C_ASSOC_ALTER_CONTEXT_CONF },
{ ASSOC_CLASS_PKT, RPC_C_ASSOC_AUTH3_IND },
{ ASSOC_CLASS_PKT, RPC_C_ASSOC_SHUTDOWN_IND },
{ CALL_CLASS_PKT, RPC_C_CALL_REMOTE_ALERT_IND },
{ CALL_CLASS_PKT, RPC_C_CALL_ORPHANED }
};
INTERNAL void receive_dispatch (
rpc_cn_assoc_p_t
);
INTERNAL void receive_packet (
rpc_cn_assoc_p_t ,
rpc_cn_fragbuf_p_t * ,
rpc_cn_fragbuf_p_t * ,
unsigned32 *
);
#define RPC_CN_SEND_FAULT(call_r, st) \
{\
rpc_binding_rep_t *binding_r; \
\
rpc__cn_call_reject ((rpc_call_rep_p_t) call_r, st);\
binding_r = (rpc_binding_rep_t *) (call_r)->binding_rep; \
RPC_CN_UNLOCK (); \
rpc__cn_call_end ((rpc_call_rep_p_t *) &(call_r), &st); \
RPC_CN_LOCK (); \
RPC_BINDING_RELEASE (&binding_r, \
&st); \
}
PRIVATE void rpc__cn_network_receiver
(
rpc_cn_assoc_p_t assoc
)
{
rpc_socket_error_t serr;
volatile boolean done = false;
RPC_CN_DBG_RTN_PRINTF (rpc__cn_network_receiver);
RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
("####### assoc->%p Entered receiver thread \n", assoc));
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p call_rep->none Receiver thread starting...\n",
assoc));
while (!done && !assoc->cn_ctlblk.exit_rcvr)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p call_rep->none Entering receive loop...\n",
assoc));
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: Attemping to lock global mutex\n"));
RPC_CN_LOCK ();
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: Global mutex locked\n"));
DCETHREAD_TRY
{
while (assoc->cn_ctlblk.cn_state != RPC_C_CN_OPEN)
{
if (assoc->cn_ctlblk.cn_rcvr_thread_id == (dcethread*)0)
{
done = true;
break;
}
assoc->cn_ctlblk.cn_rcvr_waiters++;
RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
("####### assoc->%p Waiting for new connection \n", assoc));
DCETHREAD_TRY
{
RPC_COND_WAIT (assoc->cn_ctlblk.cn_rcvr_cond,
rpc_g_global_mutex);
}
DCETHREAD_CATCH(dcethread_interrupt_e)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p rcvr free'ed by acb_free\n",
assoc));
done = true;
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s",
rpc_svc_recv,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_unexpected_exc,
"rpc__cn_network_receiver" );
}
DCETHREAD_ENDTRY
assoc->cn_ctlblk.cn_rcvr_waiters--;
if (done == true)
break;
RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
("####### assoc->%p Got a new connection \n", assoc));
}
if (done)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p call_rep->none Receiver awake ... free'ed\n",
assoc));
}
else
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p call_rep->none Receiver awake ... Connection established\n",
assoc));
RPC_CN_ASSOC_ACB_INC_REF (assoc);
RPC_CN_STATS_INCR (connections);
rpc__server_incr_clients ();
DCETHREAD_TRY
{
receive_dispatch (assoc);
}
DCETHREAD_CATCH(dcethread_interrupt_e)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p receiver canceled, caught in rpc__cn_network_receiver()\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s",
rpc_svc_recv,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_unexpected_exc,
"rpc__cn_network_receiver" );
}
DCETHREAD_ENDTRY
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p call_rep->none No longer receiving...Close socket\n",
assoc));
rpc__server_decr_clients();
RPC_CN_STATS_INCR (closed_connections);
serr = RPC_SOCKET_CLOSE (assoc->cn_ctlblk.cn_sock);
if (RPC_SOCKET_IS_ERR(serr))
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS,
("(rpc__cn_network_receiver) assoc->%p desc->%p RPC_SOCKET_CLOSE failed, error = %d\n",
assoc,
assoc->cn_ctlblk.cn_sock,
RPC_SOCKET_ETOI(serr)));
}
assoc->cn_ctlblk.cn_state = RPC_C_CN_CLOSED;
DCETHREAD_TRY
{
dcethread_checkinterrupt();
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p rcvr cancel found at acb_dealloc\n",
assoc));
}
DCETHREAD_ENDTRY
rpc__cn_assoc_acb_dealloc (assoc);
DCETHREAD_TRY
{
dcethread_checkinterrupt();
}
DCETHREAD_CATCH(dcethread_interrupt_e)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p rcvr free'ed by acb_dealloc\n",
assoc));
done = true;
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s",
rpc_svc_recv,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_unexpected_exc,
"rpc__cn_network_receiver" );
}
DCETHREAD_ENDTRY
}
}
DCETHREAD_CATCH(dcethread_interrupt_e)
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s",
rpc_svc_recv,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_unexpected_exc,
"rpc__cn_network_receiver" );
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
}
DCETHREAD_ENDTRY
DCETHREAD_TRY
{
RPC_CN_UNLOCK ();
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s",
rpc_svc_recv,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_unexpected_exc,
"rpc__cn_network_receiver" );
}
DCETHREAD_ENDTRY
}
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: assoc->%p call_rep->none Receiver thread exiting...\n",
assoc));
}
INTERNAL void receive_dispatch
(
rpc_cn_assoc_p_t assoc
)
{
rpc_cn_fragbuf_p_t fragbuf_p;
rpc_cn_fragbuf_p_t ovf_fragbuf_p;
rpc_cn_call_rep_p_t call_r;
unsigned32 st;
rpc_cn_packet_p_t pktp;
unsigned8 ptype;
volatile boolean unpack_ints = false;
volatile unsigned32 i;
rpc_cn_syntax_t *pres_context;
unsigned32 auth_st;
rpc_cn_sec_context_t *sec_context;
boolean already_unpacked;
st = rpc_s_ok;
fragbuf_p = NULL;
ovf_fragbuf_p = NULL;
call_r = NULL;
sec_context = NULL;
for (i = 0;; i++)
{
RPC_LOG_CN_PROCESS_PKT_NTR;
assoc->security.assoc_next_rcv_seq = i;
DCETHREAD_TRY
{
receive_packet (assoc, &fragbuf_p, &ovf_fragbuf_p, &st);
}
DCETHREAD_CATCH(dcethread_interrupt_e)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p receiver canceled, caught in receive_dispatch()\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
st = rpc_s_connection_closed;
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s",
rpc_svc_recv,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_unexpected_exc,
"receive_dispatch" );
}
DCETHREAD_ENDTRY
if (st != rpc_s_ok)
{
break;
}
already_unpacked = false;
assert(fragbuf_p != NULL);
pktp = (rpc_cn_packet_p_t) fragbuf_p->data_p;
RPC_CN_PKT_TRC (pktp);
RPC_CN_PKT_DUMP (pktp, fragbuf_p->data_size);
RPC_CN_STATS_INCR (pstats[RPC_CN_PKT_PTYPE (pktp)].rcvd);
RPC_CN_STATS_INCR (pkts_rcvd);
ptype = RPC_CN_PKT_PTYPE (pktp);
if ( (ptype > RPC_C_CN_PKT_MAX_TYPE) ||
(packet_info_table[ptype].class == DGRAM_CLASS_PKT))
{
st = rpc_s_protocol_error;
break;
}
if (i == 0)
{
NDR_UNPACK_DREP (&(RPC_CN_ASSOC_NDR_FORMAT (assoc)),
RPC_CN_PKT_DREP (pktp));
if ((NDR_DREP_INT_REP (RPC_CN_PKT_DREP (pktp)) !=
NDR_LOCAL_INT_REP))
{
unpack_ints = true;
}
else
{
unpack_ints = false;
}
}
else
{
if (!(ptype == RPC_C_CN_PKT_BIND) &&
((RPC_CN_PKT_VERS (pktp) != RPC_C_CN_PROTO_VERS) ||
(RPC_CN_PKT_VERS_MINOR (pktp) > RPC_C_CN_PROTO_VERS_MINOR)))
{
st = rpc_s_rpc_prot_version_mismatch;
break;
}
}
auth_st = rpc_s_ok;
if (RPC_CN_PKT_AUTH_TLR_PRESENT (pktp))
{
rpc_cn_auth_tlr_t *auth_tlr;
unsigned16 auth_len;
unsigned32 key_id;
unsigned16 frag_len;
if ((unpack_ints) &&
((ptype == RPC_C_CN_PKT_BIND) ||
(ptype == RPC_C_CN_PKT_BIND_ACK) ||
(ptype == RPC_C_CN_PKT_ALTER_CONTEXT) ||
(ptype == RPC_C_CN_PKT_ALTER_CONTEXT_RESP) ||
(ptype == RPC_C_CN_PKT_BIND_NAK) ||
(ptype == RPC_C_CN_PKT_AUTH3)))
{
assoc->raw_packet_p = rpc__cn_fragbuf_alloc (true);
assoc->raw_packet_p->data_size = fragbuf_p->data_size;
memcpy (assoc->raw_packet_p->data_p,
fragbuf_p->data_p,
fragbuf_p->data_size);
}
auth_len = RPC_CN_PKT_AUTH_LEN (pktp);
if (unpack_ints)
{
SWAB_INPLACE_16 (auth_len);
}
auth_tlr = (rpc_cn_auth_tlr_t *) ((unsigned8 *)(pktp) +
fragbuf_p->data_size -
(auth_len + RPC_CN_PKT_SIZEOF_COM_AUTH_TLR));
if ( ((unsigned8 *)(auth_tlr) < (unsigned8 *)(pktp)) ||
((unsigned8 *)(auth_tlr) > (unsigned8 *)(pktp) + fragbuf_p->data_size) ||
((unsigned8 *)(auth_tlr) + auth_len < (unsigned8 *)(pktp)) ||
((unsigned8 *)(auth_tlr) + auth_len > (unsigned8 *)(pktp) + fragbuf_p->data_size) )
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p invalid auth_tlr\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
st = rpc_s_protocol_error;
break;
}
key_id = auth_tlr->key_id;
if (unpack_ints)
{
SWAB_INPLACE_32 (key_id);
}
if ((ptype != RPC_C_CN_PKT_BIND) &&
(ptype != RPC_C_CN_PKT_ALTER_CONTEXT) &&
(ptype != RPC_C_CN_PKT_BIND_ACK) &&
(ptype != RPC_C_CN_PKT_ALTER_CONTEXT_RESP))
{
rpc_authn_protocol_id_t authn_protocol = rpc_c_authn_none;
rpc__cn_assoc_sec_lkup_by_id (assoc,
key_id,
&sec_context,
&auth_st);
if (auth_st == rpc_s_ok)
{
authn_protocol = RPC_CN_AUTH_CVT_ID_WIRE_TO_API (auth_tlr->auth_type, &auth_st);
}
if (auth_st == rpc_s_ok)
{
RPC_CN_AUTH_RECV_CHECK (authn_protocol,
&assoc->security,
sec_context,
(rpc_cn_common_hdr_t *)pktp,
fragbuf_p->data_size,
0,
auth_tlr,
unpack_ints,
&auth_st);
if (auth_st == rpc_s_ok)
{
if (unpack_ints)
{
st = rpc__cn_unpack_hdr (pktp, fragbuf_p->data_size);
if (st != rpc_s_ok)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p auth rpc__cn_unpack_hdr failed\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
break;
}
already_unpacked = true;
}
auth_len = RPC_CN_PKT_AUTH_LEN (pktp);
auth_tlr = (rpc_cn_auth_tlr_t *) ((unsigned8 *)(pktp) +
fragbuf_p->data_size -
(auth_len
+
RPC_CN_PKT_SIZEOF_COM_AUTH_TLR));
if ( ((unsigned8 *)(auth_tlr) < (unsigned8 *)(pktp)) ||
((unsigned8 *)(auth_tlr) > (unsigned8 *)(pktp) + fragbuf_p->data_size) ||
((unsigned8 *)(auth_tlr) + auth_len < (unsigned8 *)(pktp)) ||
((unsigned8 *)(auth_tlr) + auth_len > (unsigned8 *)(pktp) + fragbuf_p->data_size) )
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p invalid auth_tlr in sec context\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
st = rpc_s_protocol_error;
break;
}
frag_len = RPC_CN_PKT_FRAG_LEN (pktp);
if ( (frag_len > fragbuf_p->data_size) || (frag_len < auth_tlr->stub_pad_length) )
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p invalid frag_len\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
st = rpc_s_protocol_error;
break;
}
frag_len -= auth_tlr->stub_pad_length;
RPC_CN_PKT_FRAG_LEN (pktp) = frag_len;
if (fragbuf_p->data_size < auth_tlr->stub_pad_length)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p invalid stub_pad_length\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
st = rpc_s_protocol_error;
break;
}
fragbuf_p->data_size -= auth_tlr->stub_pad_length;
}
else
{
if (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT)
{
(*fragbuf_p->fragbuf_dealloc)(fragbuf_p);
assert(sec_context != NULL);
sec_context->sec_status = auth_st;
RPC_CN_ASSOC_WAKEUP (assoc);
continue;
}
else
{
dce_error_string_t error_text;
int temp_status;
dce_error_inq_text(auth_st, error_text, &temp_status);
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s %x",
rpc_svc_recv,
svc_c_sev_error,
rpc_m_call_failed_s,
"RPC_CN_AUTH_RECV_CHECK",
error_text );
if (packet_info_table[ptype].class == ASSOC_CLASS_PKT)
{
break;
}
}
}
}
}
}
else
{
if ((assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT) &&
(ptype == RPC_C_CN_PKT_RESPONSE) &&
(RPC_CN_PKT_AUTH_REQUIRED(assoc->call_rep->binding_rep->auth_info)))
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: auth_info %p\n", assoc->call_rep->binding_rep->auth_info));
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: should not continue further with this PDU\n"));
(*fragbuf_p->fragbuf_dealloc)(fragbuf_p);
st = rpc_s_authn_level_mismatch;
RPC_CN_ASSOC_WAKEUP (assoc);
break;
}
}
if (unpack_ints && !already_unpacked)
{
st = rpc__cn_unpack_hdr (pktp, fragbuf_p->data_size);
if (st != rpc_s_ok)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p rpc__cn_unpack_hdr failed\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
st = rpc_s_connection_closed;
break;
}
}
if (packet_info_table[ptype].class == CALL_CLASS_PKT)
{
if (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT &&
assoc->alter_call_id >= 0 &&
assoc->alter_call_id == RPC_CN_PKT_CALL_ID (pktp))
{
RPC_CN_ASSOC_EVAL_NETWORK_EVENT (assoc,
RPC_C_ASSOC_ABORT_REQ,
fragbuf_p,
st);
}
else if ((ptype == RPC_C_CN_PKT_REQUEST)
&&
(RPC_CN_PKT_FLAGS (pktp) & RPC_C_CN_FLAGS_FIRST_FRAG))
{
call_r = (rpc_cn_call_rep_t *)
rpc__list_element_alloc (&rpc_g_cn_call_lookaside_list,
true);
if (call_r == NULL)
{
st = rpc_s_no_memory;
break;
}
call_r->common.is_server = true;
rpc__cn_assoc_push_call (assoc, call_r, &st);
if (st != rpc_s_ok)
{
assoc->call_rep = NULL;
rpc__list_element_free (&rpc_g_cn_call_lookaside_list,
(dce_pointer_t) call_r);
break;
}
rpc__cn_sm_init (rpc_g_cn_server_call_sm,
rpc_g_cn_server_call_action_tbl,
&(call_r->call_state),
rpc_c_cn_svr_call);
call_r->num_pkts = 0;
call_r->sec = sec_context;
call_r->cn_call_status = rpc_s_ok;
call_r->last_frag_received = false;
call_r->call_executed = false;
call_r->common.u.server.cthread.is_queued = false;
call_r->prot_tlr = NULL;
{
int i;
for( i=1; i<RPC_C_MAX_IOVEC_LEN; i++ ) {
call_r->buffered_output.iov.elt[i].buff_addr = NULL;
call_r->buffered_output.iov.elt[i].buff_dealloc = NULL;
}
}
call_r->common.u.server.cancel.accepting = true;
call_r->common.u.server.cancel.queuing = true;
call_r->common.u.server.cancel.had_pending = false;
call_r->common.u.server.cancel.count = 0;
call_r->u.server.cancel.local_count = 0;
if (RPC_CN_PKT_FLAGS (pktp) & RPC_C_CN_FLAGS_OBJECT_UUID)
{
call_r->binding_rep =
rpc__binding_alloc (true,
&RPC_CN_PKT_OBJECT (pktp),
RPC_C_PROTOCOL_ID_NCACN,
NULL,
&st);
}
else
{
call_r->binding_rep =
rpc__binding_alloc (true,
&uuid_g_nil_uuid,
RPC_C_PROTOCOL_ID_NCACN,
NULL,
&st);
}
if (st != rpc_s_ok)
{
break;
}
((rpc_cn_binding_rep_t *)call_r->binding_rep)->grp_id
= assoc->assoc_grp_id;
call_r->assoc = assoc;
if (!sec_context)
{
sec_context = assoc->security.assoc_current_sec_context;
}
if (sec_context)
{
call_r->binding_rep->auth_info = sec_context->sec_info;
RPC_CN_AUTH_ADD_REFERENCE(sec_context->sec_info);
}
call_r->binding_rep->transport_info = assoc->transport_info;
rpc__transport_info_retain(assoc->transport_info);
RPC_CN_POST_FIRST_CALL_SM_EVENT (call_r,
assoc,
packet_info_table[ptype].event,
fragbuf_p,
st);
if (st != rpc_s_ok)
{
RPC_CN_SEND_FAULT (call_r, st);
fragbuf_p = NULL;
continue;
}
if (auth_st != rpc_s_ok)
{
RPC_CN_SEND_FAULT (call_r, auth_st);
fragbuf_p = NULL;
continue;
}
rpc__cn_assoc_syntax_lkup_by_id (assoc,
RPC_CN_PKT_PRES_CONT_ID (pktp),
&pres_context,
&st);
if (st != rpc_s_ok)
{
RPC_CN_SEND_FAULT (call_r, st);
fragbuf_p = NULL;
continue;
}
call_r->u.server.if_id = &pres_context->syntax_abstract_id.id;
call_r->u.server.if_vers = pres_context->syntax_abstract_id.version;
call_r->transfer_syntax.index = pres_context->syntax_vector_index;
call_r->transfer_syntax.convert_epv = pres_context->syntax_epv;
call_r->u.server.ihint = pres_context->syntax_ihint;
call_r->context_id = pres_context->syntax_pres_id;
rpc__cthread_invoke_null ((rpc_call_rep_p_t) call_r,
&call_r->binding_rep->obj,
call_r->u.server.if_id,
call_r->u.server.if_vers,
(unsigned32) call_r->opnum,
rpc__cn_call_executor,
(dce_pointer_t) call_r,
&st);
if (st == rpc_s_call_queued)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p call queued\n",
call_r,
assoc,
assoc->cn_ctlblk.cn_sock));
st = rpc_s_ok;
}
else
{
if (st != rpc_s_ok)
{
RPC_CN_SEND_FAULT (call_r, st);
fragbuf_p = NULL;
continue;
}
}
RPC_CN_STATS_INCR (calls_rcvd);
}
else
{
RPC_CN_POST_CALL_SM_EVENT (assoc,
packet_info_table[ptype].event,
fragbuf_p,
st);
}
}
else
{
RPC_CN_ASSOC_EVAL_NETWORK_EVENT (assoc,
packet_info_table[ptype].event,
fragbuf_p,
st);
}
RPC_CN_UNLOCK ();
dcethread_yield ();
RPC_CN_LOCK ();
fragbuf_p = NULL;
RPC_LOG_CN_PROCESS_PKT_XIT;
}
rpc__cn_assoc_post_error (assoc, st);
if (fragbuf_p)
{
(*fragbuf_p->fragbuf_dealloc)(fragbuf_p);
}
if (ovf_fragbuf_p)
{
(*ovf_fragbuf_p->fragbuf_dealloc)(ovf_fragbuf_p);
}
}
INTERNAL void receive_packet
(
rpc_cn_assoc_p_t assoc,
rpc_cn_fragbuf_p_t *fragbuf_p,
rpc_cn_fragbuf_p_t *ovf_fragbuf_p,
unsigned32 *st
)
{
rpc_cn_fragbuf_t * volatile fbp;
volatile unsigned16 frag_length;
size_t bytes_rcvd = 0;
rpc_socket_iovec_t iov;
volatile rpc_socket_error_t serr = 0;
signed32 need_bytes;
static rpc_addr_p_t addr = NULL;
RPC_LOG_CN_RCV_PKT_NTR;
CODING_ERROR (st);
fbp = NULL;
*fragbuf_p = NULL;
if (*ovf_fragbuf_p != NULL)
{
fbp = *ovf_fragbuf_p;
*ovf_fragbuf_p = NULL;
}
if (fbp == NULL)
{
fbp = rpc__cn_fragbuf_alloc (true);
}
if (fbp->data_size >= RPC_C_CN_FRAGLEN_HEADER_BYTES)
{
frag_length = RPC_CN_PKT_FRAG_LEN ((rpc_cn_packet_p_t)(fbp->data_p));
if (NDR_DREP_INT_REP(RPC_CN_PKT_DREP((rpc_cn_packet_p_t)fbp->data_p))
!= NDR_LOCAL_INT_REP)
{
SWAB_INPLACE_16 (frag_length);
}
need_bytes = frag_length - fbp->data_size;
}
else
{
frag_length = 0;
need_bytes = fbp->max_data_size - fbp->data_size;
}
while (need_bytes > 0)
{
iov.iov_base = (byte_p_t)((unsigned8 *)(fbp->data_p) + fbp->data_size);
iov.iov_len = need_bytes;
RPC_CN_UNLOCK ();
DCETHREAD_TRY
{
#ifdef NON_CANCELLABLE_IO
dcethread_enableasync_throw(1);
dcethread_checkinterrupt();
#endif
serr = rpc__socket_recvmsg(
assoc->cn_ctlblk.cn_sock,
&iov,
1,
addr,
&bytes_rcvd);
#ifdef NON_CANCELLABLE_IO
dcethread_enableasync_throw(0);
#endif
}
DCETHREAD_CATCH (dcethread_interrupt_e)
{
#ifdef NON_CANCELLABLE_IO
dcethread_enableasync_throw(0);
#endif
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p receiver canceled, caught in receive_packet()\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
RPC_CN_LOCK ();
if (fbp)
{
(*(fbp)->fragbuf_dealloc)(fbp);
}
DCETHREAD_RERAISE;
}
DCETHREAD_CATCH_ALL(THIS_CATCH)
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%s",
rpc_svc_recv,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_unexpected_exc,
"receive_packet" );
}
DCETHREAD_ENDTRY
RPC_CN_LOCK ();
while (assoc->cn_ctlblk.in_sendmsg)
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p waiting for sendmsg to complete...\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
assoc->cn_ctlblk.waiting_for_sendmsg_complete = true;
RPC_COND_WAIT (assoc->cn_ctlblk.cn_rcvr_cond,
rpc_g_global_mutex);
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p sendmsg complete\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock));
assoc->cn_ctlblk.waiting_for_sendmsg_complete = false;
}
if ((RPC_SOCKET_IS_ERR (serr))
||
(bytes_rcvd == 0)
||
(assoc->assoc_local_status != rpc_s_ok)
||
(assoc->assoc_status != rpc_s_ok))
{
if (rpc__naf_is_connect_closed (assoc->cn_ctlblk.cn_sock, st))
{
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p connection closed recvmsg failed serr = %x, bytes_rcvd = %ld\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock,
serr,
bytes_rcvd));
(*fbp->fragbuf_dealloc)(fbp);
*st = rpc_s_connection_closed;
return;
}
}
RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
("CN: call_rep->%p assoc->%p desc->%p received %ld bytes\n",
assoc->call_rep,
assoc,
assoc->cn_ctlblk.cn_sock,
bytes_rcvd));
fbp->data_size += bytes_rcvd;
if ((frag_length == 0) && (fbp->data_size >= RPC_C_CN_FRAGLEN_HEADER_BYTES))
{
frag_length = RPC_CN_PKT_FRAG_LEN ((rpc_cn_packet_p_t)(fbp->data_p));
if (NDR_DREP_INT_REP( RPC_CN_PKT_DREP((rpc_cn_packet_p_t)fbp->data_p) ) != NDR_LOCAL_INT_REP)
{
SWAB_INPLACE_16 (frag_length);
}
{
unsigned32 ptype;
ptype = RPC_CN_PKT_PTYPE((rpc_cn_packet_p_t)fbp->data_p);
if ((ptype != RPC_C_CN_PKT_BIND) &&
(ptype != RPC_C_CN_PKT_BIND_NAK) &&
((RPC_CN_PKT_VERS ((rpc_cn_packet_p_t)fbp->data_p) != RPC_C_CN_PROTO_VERS) ||
(RPC_CN_PKT_VERS_MINOR ((rpc_cn_packet_p_t)fbp->data_p) != assoc->assoc_vers_minor)))
{
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%x %s %x %x",
rpc_svc_cn_pkt,
svc_c_sev_warning,
rpc_m_prot_mismatch,
assoc,
rpc__cn_pkt_name(ptype),
RPC_CN_PKT_VERS ((rpc_cn_packet_p_t)fbp->data_p),
RPC_CN_PKT_VERS_MINOR ((rpc_cn_packet_p_t)fbp->data_p) );
}
}
if (frag_length > rpc_g_cn_large_frag_size)
{
unsigned32 ptype;
ptype = RPC_CN_PKT_PTYPE((rpc_cn_packet_p_t)fbp->data_p);
rpc_dce_svc_printf (
__FILE__, __LINE__,
"%x %d %d",
rpc_svc_cn_pkt,
svc_c_sev_warning,
rpc_m_frag_toobig,
assoc,
frag_length,
rpc_g_cn_large_frag_size );
if ((ptype == RPC_C_CN_PKT_BIND) ||
(ptype == RPC_C_CN_PKT_ALTER_CONTEXT))
{
rpc_cn_fragbuf_t * volatile tmp;
tmp = rpc__cn_fragbuf_alloc_dyn(frag_length);
tmp->data_size = fbp->data_size;
memcpy(tmp->data_p, fbp->data_p, fbp->data_size);
(*fbp->fragbuf_dealloc)(fbp);
fbp = tmp;
}
else
{
*st = rpc_s_protocol_error;
(*fbp->fragbuf_dealloc)(fbp);
return;
}
}
}
if (frag_length == 0)
{
need_bytes = fbp->max_data_size - fbp->data_size;
}
else
{
need_bytes = frag_length - fbp->data_size;
}
}
if (need_bytes < 0)
{
*ovf_fragbuf_p = rpc__cn_fragbuf_alloc (true);
(*ovf_fragbuf_p)->data_size = abs(need_bytes);
fbp->data_size = frag_length;
memcpy ((*ovf_fragbuf_p)->data_p,
(dce_pointer_t)((unsigned8 *)(fbp->data_p) + fbp->data_size),
(*ovf_fragbuf_p)->data_size);
}
*fragbuf_p = fbp;
*st = rpc_s_ok;
RPC_LOG_CN_RCV_PKT_XIT;
}