static Sr__Msg * cm_message_recv(const int fd) { uint8_t buf1[SR_MSG_PREAM_SIZE] = { 0, }, *buf2 = NULL; size_t len = 0, pos = 0; size_t msg_size = 0; /* read first 4 bytes with length of the message */ while (pos < SR_MSG_PREAM_SIZE) { len = recv(fd, buf1 + pos, SR_MSG_PREAM_SIZE - pos, 0); assert_int_not_equal(len, -1); if (0 == len) { return NULL; /* disconnect */ } pos += len; } msg_size = sr_buff_to_uint32(buf1); assert_true((msg_size > 0) && (msg_size <= SR_MAX_MSG_SIZE)); buf2 = calloc(msg_size, sizeof(*buf2)); assert_non_null(buf2); /* read the rest of the message */ pos = 0; while (pos < msg_size) { len = recv(fd, buf2 + pos, msg_size - pos, 0); assert_int_not_equal(len, -1); if (0 == len) { return NULL; /* disconnect */ } pos += len; } Sr__Msg *msg = sr__msg__unpack(NULL, msg_size, (const uint8_t*)buf2); free(buf2); return msg; }
/* * @brief Receives a message on provided connection (blocks until a message is received). */ static int cl_message_recv(sr_conn_ctx_t *conn_ctx, Sr__Msg **msg, sr_mem_ctx_t *sr_mem_resp) { size_t len = 0, pos = 0; size_t msg_size = 0; sr_mem_ctx_t *sr_mem = sr_mem_resp; int rc = 0; /* expand the buffer if needed */ rc = cl_conn_msg_buf_expand(conn_ctx, SR_MSG_PREAM_SIZE); if (SR_ERR_OK != rc) { SR_LOG_ERR_MSG("Cannot expand buffer for the message."); return rc; } /* read at least first 4 bytes with length of the message */ while (pos < SR_MSG_PREAM_SIZE) { len = recv(conn_ctx->fd, conn_ctx->msg_buf, conn_ctx->msg_buf_size, 0); if (-1 == len) { if (errno == EINTR) { continue; } if (EAGAIN == errno || EWOULDBLOCK == errno) { SR_LOG_ERR_MSG("While waiting for a response, timeout has expired."); return SR_ERR_TIME_OUT; } SR_LOG_ERR("Error by receiving of the message: %s.", sr_strerror_safe(errno)); return SR_ERR_DISCONNECT; } if (0 == len) { SR_LOG_ERR_MSG("Sysrepo server disconnected."); return SR_ERR_DISCONNECT; } pos += len; } msg_size = sr_buff_to_uint32(conn_ctx->msg_buf); /* check message size bounds */ if ((msg_size <= 0) || (msg_size > SR_MAX_MSG_SIZE)) { SR_LOG_ERR("Invalid message size in the message preamble (%zu).", msg_size); return SR_ERR_MALFORMED_MSG; } /* expand the buffer if needed */ rc = cl_conn_msg_buf_expand(conn_ctx, (msg_size + SR_MSG_PREAM_SIZE)); if (SR_ERR_OK != rc) { SR_LOG_ERR_MSG("Cannot expand buffer for the message."); return rc; } /* read the rest of the message */ while (pos < (msg_size + SR_MSG_PREAM_SIZE)) { len = recv(conn_ctx->fd, (conn_ctx->msg_buf + pos), (conn_ctx->msg_buf_size - pos), 0); if (-1 == len) { if (errno == EINTR) { continue; } if (EAGAIN == errno || EWOULDBLOCK == errno) { SR_LOG_ERR_MSG("While waiting for a response, timeout has expired."); return SR_ERR_TIME_OUT; } SR_LOG_ERR("Error by receiving of the message: %s.", sr_strerror_safe(errno)); return SR_ERR_DISCONNECT; } if (0 == len) { SR_LOG_ERR_MSG("Sysrepo server disconnected."); return SR_ERR_DISCONNECT; } pos += len; } /* unpack the message */ if (NULL == sr_mem) { rc = sr_mem_new(msg_size, &sr_mem); CHECK_RC_MSG_RETURN(rc, "Failed to create a new Sysrepo memory context."); } ProtobufCAllocator allocator = sr_get_protobuf_allocator(sr_mem); *msg = sr__msg__unpack(&allocator, msg_size, (const uint8_t*)(conn_ctx->msg_buf + SR_MSG_PREAM_SIZE)); if (NULL == *msg) { if (NULL == sr_mem_resp) { sr_mem_free(sr_mem); } SR_LOG_ERR_MSG("Malformed message received."); return SR_ERR_MALFORMED_MSG; } /* associate message with context */ if (NULL != sr_mem) { (*msg)->_sysrepo_mem_ctx = (uint64_t)sr_mem; ++sr_mem->obj_count; } return SR_ERR_OK; }