+static int recv_reply(struct lttcomm_relayd_sock *rsock, void *data, size_t size)
+{
+ int ret;
+
+ if (rsock->sock.fd < 0) {
+ return -ECONNRESET;
+ }
+
+ DBG3("Relayd waiting for reply of size %zu", size);
+
+ ret = rsock->sock.ops->recvmsg(&rsock->sock, data, size, 0);
+ if (ret <= 0 || ret != size) {
+ if (ret == 0) {
+ /* Orderly shutdown. */
+ DBG("Socket %d has performed an orderly shutdown", rsock->sock.fd);
+ } else {
+ DBG("Receiving reply failed on sock %d for size %zu with ret %d",
+ rsock->sock.fd, size, ret);
+ }
+ /* Always return -1 here and the caller can use errno. */
+ ret = -1;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Starting from 2.11, RELAYD_CREATE_SESSION payload (session_name & hostname)
+ * have no length restriction on the sender side.
+ * Length for both payloads is stored in the msg struct. A new dynamic size
+ * payload size is introduced.
+ */
+static int relayd_create_session_2_11(struct lttcomm_relayd_sock *rsock,
+ const char *session_name, const char *hostname,
+ int session_live_timer, unsigned int snapshot,
+ uint64_t sessiond_session_id, const lttng_uuid sessiond_uuid,
+ const uint64_t *current_chunk_id,
+ time_t creation_time)
+{
+ int ret;
+ struct lttcomm_relayd_create_session_2_11 *msg = NULL;
+ size_t session_name_len;
+ size_t hostname_len;
+ size_t msg_length;
+
+ /* The two names are sent with a '\0' delimiter between them. */
+ session_name_len = strlen(session_name) + 1;
+ hostname_len = strlen(hostname) + 1;
+
+ msg_length = sizeof(*msg) + session_name_len + hostname_len;
+ msg = zmalloc(msg_length);
+ if (!msg) {
+ PERROR("zmalloc create_session_2_11 command message");
+ ret = -1;
+ goto error;
+ }
+
+ assert(session_name_len <= UINT32_MAX);
+ msg->session_name_len = htobe32(session_name_len);
+
+ assert(hostname_len <= UINT32_MAX);
+ msg->hostname_len = htobe32(hostname_len);
+
+ if (lttng_strncpy(msg->names, session_name, session_name_len)) {
+ ret = -1;
+ goto error;
+ }
+ if (lttng_strncpy(msg->names + session_name_len, hostname, hostname_len)) {
+ ret = -1;
+ goto error;
+ }
+
+ msg->live_timer = htobe32(session_live_timer);
+ msg->snapshot = !!snapshot;
+
+ lttng_uuid_copy(msg->sessiond_uuid, sessiond_uuid);
+ msg->session_id = htobe64(sessiond_session_id);
+
+ if (current_chunk_id) {
+ LTTNG_OPTIONAL_SET(&msg->current_chunk_id,
+ htobe64(*current_chunk_id));
+ }
+
+ msg->creation_time = htobe64((uint64_t) creation_time);
+
+ /* Send command */
+ ret = send_command(rsock, RELAYD_CREATE_SESSION, msg, msg_length, 0);
+ if (ret < 0) {
+ goto error;
+ }
+error:
+ free(msg);
+ return ret;
+}
+/*
+ * From 2.4 to 2.10, RELAYD_CREATE_SESSION takes additional parameters to
+ * support the live reading capability.
+ */
+static int relayd_create_session_2_4(struct lttcomm_relayd_sock *rsock,
+ const char *session_name, const char *hostname,
+ int session_live_timer, unsigned int snapshot)
+{
+ int ret;
+ struct lttcomm_relayd_create_session_2_4 msg;
+
+ if (lttng_strncpy(msg.session_name, session_name,
+ sizeof(msg.session_name))) {
+ ret = -1;
+ goto error;
+ }
+ if (lttng_strncpy(msg.hostname, hostname, sizeof(msg.hostname))) {
+ ret = -1;
+ goto error;
+ }
+ msg.live_timer = htobe32(session_live_timer);
+ msg.snapshot = htobe32(snapshot);
+
+ /* Send command */
+ ret = send_command(rsock, RELAYD_CREATE_SESSION, &msg, sizeof(msg), 0);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * RELAYD_CREATE_SESSION from 2.1 to 2.3.
+ */
+static int relayd_create_session_2_1(struct lttcomm_relayd_sock *rsock)
+{
+ int ret;
+
+ /* Send command */
+ ret = send_command(rsock, RELAYD_CREATE_SESSION, NULL, 0, 0);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Send a RELAYD_CREATE_SESSION command to the relayd with the given socket and
+ * set session_id of the relayd if we have a successful reply from the relayd.
+ *
+ * On success, return 0 else a negative value which is either an errno error or
+ * a lttng error code from the relayd.
+ */
+int relayd_create_session(struct lttcomm_relayd_sock *rsock,
+ uint64_t *relayd_session_id,
+ const char *session_name, const char *hostname,
+ int session_live_timer,
+ unsigned int snapshot, uint64_t sessiond_session_id,
+ const lttng_uuid sessiond_uuid,
+ const uint64_t *current_chunk_id,
+ time_t creation_time)
+{
+ int ret;
+ struct lttcomm_relayd_status_session reply;
+
+ assert(rsock);
+ assert(relayd_session_id);
+
+ DBG("Relayd create session");
+
+ if (rsock->minor < 4) {
+ /* From 2.1 to 2.3 */
+ ret = relayd_create_session_2_1(rsock);
+ } else if (rsock->minor >= 4 && rsock->minor < 11) {
+ /* From 2.4 to 2.10 */
+ ret = relayd_create_session_2_4(rsock, session_name,
+ hostname, session_live_timer, snapshot);
+ } else {
+ /* From 2.11 to ... */
+ ret = relayd_create_session_2_11(rsock, session_name,
+ hostname, session_live_timer, snapshot,
+ sessiond_session_id, sessiond_uuid,
+ current_chunk_id, creation_time);
+ }
+
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Receive response */
+ ret = recv_reply(rsock, (void *) &reply, sizeof(reply));
+ if (ret < 0) {
+ goto error;
+ }
+
+ reply.session_id = be64toh(reply.session_id);
+ reply.ret_code = be32toh(reply.ret_code);
+
+ /* Return session id or negative ret code. */
+ if (reply.ret_code != LTTNG_OK) {
+ ret = -1;
+ ERR("Relayd create session replied error %d", reply.ret_code);
+ goto error;
+ } else {
+ ret = 0;
+ *relayd_session_id = reply.session_id;
+ }
+
+ DBG("Relayd session created with id %" PRIu64, reply.session_id);
+
+error:
+ return ret;
+}
+
+static int relayd_add_stream_2_1(struct lttcomm_relayd_sock *rsock,
+ const char *channel_name, const char *pathname)
+{
+ int ret;
+ struct lttcomm_relayd_add_stream msg;
+
+ memset(&msg, 0, sizeof(msg));
+ if (lttng_strncpy(msg.channel_name, channel_name,
+ sizeof(msg.channel_name))) {
+ ret = -1;
+ goto error;
+ }
+
+ if (lttng_strncpy(msg.pathname, pathname,
+ sizeof(msg.pathname))) {
+ ret = -1;
+ goto error;
+ }
+
+ /* Send command */
+ ret = send_command(rsock, RELAYD_ADD_STREAM, (void *) &msg, sizeof(msg), 0);
+ if (ret < 0) {
+ ret = -1;
+ goto error;
+ }
+ ret = 0;
+error:
+ return ret;
+}
+
+static int relayd_add_stream_2_2(struct lttcomm_relayd_sock *rsock,
+ const char *channel_name, const char *pathname,
+ uint64_t tracefile_size, uint64_t tracefile_count)