static void RpcInStop(RpcChannel *chan) { BackdoorChannel *bdoor = chan->_private; g_static_mutex_lock(&bdoor->outLock); if (bdoor->out != NULL) { if (bdoor->outStarted) { RpcOut_stop(bdoor->out); } bdoor->outStarted = FALSE; } else { ASSERT(!bdoor->outStarted); } g_static_mutex_unlock(&bdoor->outLock); if (bdoor->in != NULL) { if (bdoor->inStarted) { RpcIn_stop(bdoor->in); } bdoor->inStarted = FALSE; } else { ASSERT(!bdoor->inStarted); } }
static void BkdoorChannelStop(RpcChannel *chan) { BackdoorChannel *bdoor = chan->_private; if (bdoor->out != NULL) { if (chan->outStarted) { RpcOut_stop(bdoor->out); } chan->outStarted = FALSE; } else { ASSERT(!chan->outStarted); } }
static gboolean BkdoorChannelSend(RpcChannel *chan, char const *data, size_t dataLen, char **result, size_t *resultLen) { gboolean ret = FALSE; const char *reply; size_t replyLen; BackdoorChannel *bdoor = chan->_private; if (!chan->outStarted) { goto exit; } ret = RpcOut_send(bdoor->out, data, dataLen, &reply, &replyLen); /* * This is a hack to try to work around bug 393650 without having to revert * to the old behavior of opening and closing an RpcOut channel for every * outgoing message. The issue here is that it's possible for the code to * try to write to the channel when a "reset" has just happened. In these * cases, the current RpcOut channel is not valid anymore, and we'll get an * error. The RpcOut lib doesn't really reply with a useful error, but it * does have consistent error messages starting with "RpcOut:". * * So, if the error is one of those messages, restart the RpcOut channel and * try to send the message again. If this second attempt fails, then give up. * * This is not 100% break-proof: a reset can still occur after we open the * new channel and before we try to re-send the message. But that's a race * that we can't easily fix, and exists even in code that just uses the * RpcOut_SendOne() API. Also, if some host handler returns an error that * starts with "RpcOut:", it will trigger this; but I don't think we have * any such handlers. */ if (!ret && reply != NULL && replyLen > sizeof "RpcOut: " && g_str_has_prefix(reply, "RpcOut: ")) { Debug("RpcOut failure, restarting channel.\n"); RpcOut_stop(bdoor->out); if (RpcOut_start(bdoor->out)) { ret = RpcOut_send(bdoor->out, data, dataLen, &reply, &replyLen); } else { Warning("Couldn't restart RpcOut channel; bad things may happen " "until the RPC channel is reset.\n"); chan->outStarted = FALSE; } } /* * A lot of this logic is just replicated from rpcout.c:RpcOut_SendOneRaw(). * Look there for comments about a few details. */ if (result != NULL) { if (reply != NULL) { *result = Util_SafeMalloc(replyLen + 1); memcpy(*result, reply, replyLen); (*result)[replyLen] = '\0'; } else { *result = NULL; } } if (resultLen != NULL) { *resultLen = replyLen; } exit: return ret; }
Bool RpcOut_SendOneRaw(void *request, // IN: RPCI command size_t reqLen, // IN: Size of request buffer char **reply, // OUT: Result size_t *repLen) // OUT: Length of the result { Bool status; RpcOut *out = NULL; char const *myReply; size_t myRepLen; status = FALSE; Debug("Rpci: Sending request='%s'\n", (char *)request); out = RpcOut_Construct(); if (out == NULL) { myReply = "RpcOut: Unable to create the RpcOut object"; myRepLen = strlen(myReply); goto sent; } else if (RpcOut_start(out) == FALSE) { myReply = "RpcOut: Unable to open the communication channel"; myRepLen = strlen(myReply); goto sent; } else if (RpcOut_send(out, request, reqLen, &myReply, &myRepLen) == FALSE) { /* We already have the description of the error */ goto sent; } status = TRUE; sent: Debug("Rpci: Sent request='%s', reply='%s', len=%"FMTSZ"u, status=%d\n", (char *)request, myReply, myRepLen, status); if (reply != NULL) { /* * If we got a non-NULL reply, make a copy of it, because the reply * we got back is inside the channel buffer, which will get destroyed * at the end of this function. */ if (myReply != NULL) { /* * We previously used strdup to duplicate myReply, but that * breaks if you are sending binary (not string) data over the * backdoor. Don't assume the data is a string. * * myRepLen is strlen(myReply), so we need an extra byte to * cover the NUL terminator. */ *reply = malloc(myRepLen + 1); if (*reply != NULL) { memcpy(*reply, myReply, myRepLen); /* * The message layer already writes a trailing NUL but we might * change that someday, so do it again here. */ (*reply)[myRepLen] = 0; } } else { /* * Our reply was NULL, so just pass the NULL back up to the caller. */ *reply = NULL; } /* * Only set the length if the caller wanted it and if we got a good * reply. */ if (repLen != NULL && *reply != NULL) { *repLen = myRepLen; } } if (out) { if (RpcOut_stop(out) == FALSE) { /* * We couldn't stop the channel. Free anything we allocated, give our * client a reply of NULL, and return FALSE. */ if (reply != NULL) { free(*reply); *reply = NULL; } Debug("Rpci: unable to close the communication channel\n"); status = FALSE; } RpcOut_Destruct(out); out = NULL; } return status; }