/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			struct xio_new_session_req *session_data,
			void *cb_prv_data)
{
	struct xio_msg	*req;
	int		i = 0;

	printf("**** [%p] on_new_session :%s:%d\n", session,
	       get_ip((struct sockaddr *)&session_data->src_addr),
	       get_port((struct sockaddr *)&session_data->src_addr));

	xio_accept(session, NULL, 0, NULL, 0);

	msg_pool_reset(pool);
	conn = xio_get_connection(session, ctx);

	printf("**** starting ...\n");
	while (1) {
		/* create transaction */
		req = msg_pool_get(pool);
		if (req == NULL)
			break;

		/* get pointers to internal buffers */
		req->in.header.iov_base = NULL;
		req->in.header.iov_len = 0;
		req->in.data_iovlen = 1;
		req->in.data_iov[0].iov_base = NULL;
		req->in.data_iov[0].iov_len  = ONE_MB;
		req->in.data_iov[0].mr = NULL;

		/* recycle the message and fill new request */
		msg_set(req, 1,
			test_config.hdr_len,
			test_config.data_len);

		/* try to send it */
		if (xio_send_request(conn, req) == -1) {
			printf("**** sent %d messages\n", i);
			if (xio_errno() != EAGAIN)
				printf("**** [%p] Error - xio_send_msg " \
				       "failed. %s\n",
					session,
					xio_strerror(xio_errno()));
			msg_pool_put(pool, req);
			return 0;
		}
		i++;
		if (i == 256)
			break;
	}

	return 0;
}
示例#2
0
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			  struct xio_new_session_req *req,
			  void *cb_prv_data)
{
	printf("**** [%p] on_new_session :%s:%d\n", session,
	       get_ip((struct sockaddr *)&req->src_addr),
	       get_port((struct sockaddr *)&req->src_addr));

	xio_accept(session, NULL, 0, NULL, 0);

	return 0;
}
示例#3
0
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			struct xio_new_session_req *req,
			void *cb_user_context)
{
	struct server_data  *server_data = cb_user_context;

	/* automatic accept the request */
	xio_accept(session,
		   (const char **)server_data->user_param->portals_arr,
		   server_data->user_param->portals_arr_len,
		   NULL, 0);

	return 0;
}
示例#4
0
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
                          struct xio_new_session_req *req,
                          void *cb_user_context)
{
    int			i = 0;
    struct ow_test_params	*ow_params = cb_user_context;
    struct xio_msg		*msg;

    printf("**** [%p] on_new_session :%s:%d\n", session,
           get_ip((struct sockaddr *)&req->src_addr),
           get_port((struct sockaddr *)&req->src_addr));

    xio_accept(session, NULL, 0, NULL, 0);

    if (ow_params->connection == NULL)
        ow_params->connection = xio_get_connection(session,
                                ow_params->ctx);

    for (i = 0; i < MAX_OUTSTANDING_REQS; i++) {
        /* pick message from the pool */
        msg = msg_pool_get(ow_params->pool);
        if (msg == NULL)
            break;

        /* assign buffers to the message */
        msg_write(&ow_params->msg_params, msg,
                  NULL, test_config.hdr_len,
                  NULL, test_config.data_len);

        /* ask for read receipt since the message needed to be
         * recycled to the pool */
        msg->flags = XIO_MSG_FLAG_REQUEST_READ_RECEIPT;

        /* send the message */
        if (xio_send_msg(ow_params->connection, msg) == -1) {
            printf("**** sent %d messages\n", i);
            if (xio_errno() != EAGAIN)
                printf("**** [%p] Error - xio_send_msg " \
                       "failed. %s\n",
                       session,
                       xio_strerror(xio_errno()));
            msg_pool_put(ow_params->pool, msg);
            return 0;
        }
        ow_params->nsent++;
    }
    return 0;
}
示例#5
0
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			struct xio_new_session_req *req,
			void *cb_user_context)
{
	struct portals_vec *portals;
	struct server_data *server_data = cb_user_context;

	portals = portals_get(server_data, req->uri, req->user_context);

	/* automatic accept the request */
	xio_accept(session, portals->vec, portals->vec_len, NULL, 0);

	portals_free(portals);

	return 0;
}
示例#6
0
文件: xio_server.c 项目: SUSE/accelio
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			  struct xio_new_session_req *req,
			  void *cb_user_context)
{
	struct server_data *server_data = cb_user_context;

	server_data->session = session;

	/* Automatically accept the request */
	if (!server_data->connection)
		xio_accept(session, NULL, 0, NULL, 0);
	else
		xio_reject(session, EISCONN, NULL, 0);

	return 0;
}
示例#7
0
文件: xiosrvd.c 项目: SUSE/accelio
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			  struct xio_new_session_req *req,
			  void *cb_user_context)
{
	struct server_data *server_data = (struct server_data *)cb_user_context;

	/* automatically accept the request */
	printf("new session event. session:%p\n", session);

	if (server_data->connection == NULL)
		xio_accept(session, NULL, 0, NULL, 0);
	else
		xio_reject(session, (enum xio_status)EISCONN , NULL, 0);

	return 0;
}
示例#8
0
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			  struct xio_new_session_req *req,
			  void *cb_user_context)
{
	struct test_params *test_params = cb_user_context;

	printf("**** [%p] on_new_session :%s:%d\n", session,
	       get_ip((struct sockaddr *)&req->src_addr),
	       get_port((struct sockaddr *)&req->src_addr));

	xio_accept(session, NULL, 0, NULL, 0);

	if (test_params->connection == NULL)
		test_params->connection = xio_get_connection(session,
							     test_params->ctx);


	return 0;
}
示例#9
0
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
                          struct xio_new_session_req *req,
                          void *cb_user_context)
{
    struct portals_vec *portals;
    struct server_data *server_data = (struct server_data *)cb_user_context;

    printf("**** [%p] on_new_session :%s:%d\n", session,
           get_ip((struct sockaddr *)&req->src_addr),
           get_port((struct sockaddr *)&req->src_addr));

    portals = portals_get(server_data, req->uri, req->private_data);

    /* automatic accept the request */
    xio_accept(session, portals->vec, portals->vec_len, NULL, 0);

    portals_free(portals);

    return 0;
}
示例#10
0
/*---------------------------------------------------------------------------*/
static int on_new_session(struct xio_session *session,
			  struct xio_new_session_req *req,
			  void *cb_user_context)
{
	struct test_params *test_params = cb_user_context;
	char ip[INET6_ADDRSTRLEN + 1];

	pr_info("**** [%p] on_new_session :%s:%d\n", session,
		get_ip((struct sockaddr *)&req->src_addr, ip),
		get_port((struct sockaddr *)&req->src_addr));

	test_params->session = session;

	if (!test_params->connection)
		xio_accept(session, NULL, 0, NULL, 0);
	else
		xio_reject(session, EISCONN, NULL, 0);

	return 0;
}
示例#11
0
static int server_on_new_session(struct xio_session *session,
			  struct xio_new_session_req *req,
			  void *cb_user_context)
{
	struct xio_session_attr attr;
	struct server_data *srv = xzalloc(sizeof(*srv));

	sd_debug("on new session: %p", session);

	xio_accept(session, NULL, 0, NULL, 0);

	INIT_LIST_HEAD(&srv->conn_list);

	memset(&attr, 0, sizeof(attr));
	attr.user_context = srv;
	xio_modify_session(session, &attr,
			   XIO_SESSION_ATTR_USER_CTX);

	xio_context_stop_loop(xio_get_main_ctx());

	return 0;
}
示例#12
0
/*---------------------------------------------------------------------------*/
int xio_on_setup_req_recv(struct xio_connection *connection,
			  struct xio_task *task)
{
	struct xio_msg			*msg = &task->imsg;
	struct xio_new_session_req	req;
	uint8_t				*ptr;
	uint16_t			len;
	struct xio_session_hdr		hdr;
	struct xio_session		*session = connection->session;
	int				retval;
	struct xio_session_event_data  error_event = {};

	error_event.event = XIO_SESSION_ERROR_EVENT;

	/* read session header */
	xio_session_read_header(task, &hdr);
#ifdef XIO_SESSION_DEBUG
	connection->peer_connection = hdr.connection;
	connection->peer_session = hdr.session;
#endif
	task->imsg.sn = hdr.serial_num;
	task->connection = connection;
	task->session = session;
	connection->session->setup_req = msg;

	/* read the header */
	ptr = (uint8_t *)msg->in.header.iov_base;

	memset(&req, 0, sizeof(req));

	/* session id */
	len = xio_read_uint32(&session->peer_session_id, 0, ptr);
	ptr  = ptr + len;

	/* queue depth bytes */
	len = xio_read_uint64(&session->peer_snd_queue_depth_bytes, 0, ptr);
	ptr = ptr + len;

	len = xio_read_uint64(&session->peer_rcv_queue_depth_bytes, 0, ptr);
	ptr = ptr + len;

	/* queue depth msgs */
	len = xio_read_uint16((uint16_t *)&session->peer_snd_queue_depth_msgs,
			      0, ptr);
	ptr = ptr + len;

	len = xio_read_uint16((uint16_t *)&session->peer_rcv_queue_depth_msgs,
			      0, ptr);
	ptr = ptr + len;

	/* uri length */
	len = xio_read_uint16(&req.uri_len, 0, ptr);
	ptr = ptr + len;

	/* private length */
	len = xio_read_uint16(&req.private_data_len, 0, ptr);
	ptr = ptr + len;

	if (req.uri_len) {
		req.uri =
		  (char *)kcalloc(req.uri_len, sizeof(char), GFP_KERNEL);
		if (unlikely(!req.uri)) {
			xio_set_error(ENOMEM);
			ERROR_LOG("uri allocation failed. len:%d\n",
				  req.uri_len);
			goto cleanup1;
		}

		len = xio_read_array((uint8_t *)req.uri,
				     req.uri_len, 0, ptr);
		ptr = ptr + len;
	}
	if (req.private_data_len) {
		req.private_data = kcalloc(req.private_data_len,
					   sizeof(uint8_t), GFP_KERNEL);
		if (unlikely(!req.private_data)) {
			xio_set_error(ENOMEM);
			ERROR_LOG("private data allocation failed. len:%d\n",
				  req.private_data_len);
			goto cleanup2;
		}
		len = xio_read_array((uint8_t *)req.private_data,
				     req.private_data_len,
				     0, ptr);
		ptr = ptr + len;
	}

	req.proto = (enum xio_proto)xio_nexus_get_proto(connection->nexus);
	xio_nexus_get_peer_addr(connection->nexus,
				&req.src_addr, sizeof(req.src_addr));

	/* cache the task in io queue*/
	xio_connection_queue_io_task(connection, task);

	/* notify the upper layer */
	if (connection->ses_ops.on_new_session) {
		retval = connection->ses_ops.on_new_session(
					session, &req,
					connection->cb_user_context);
		if (retval)
			goto cleanup2;
	} else {
		retval = xio_accept(session, NULL, 0, NULL, 0);
		if (retval) {
			ERROR_LOG("failed to auto accept session. session:%p\n",
				  session);
			goto cleanup2;
		}
	}

	/* Don't move session state to ONLINE. In case of multiple portals
	 * the accept moves the state to ACCEPTED until the first "HELLO"
	 * message arrives. Note that the "upper layer" may call redirect or
	 * reject.
	 */

	xio_session_notify_new_connection(session, connection);

	kfree(req.private_data);
	kfree(req.uri);

	return 0;

cleanup2:
	kfree(req.private_data);

cleanup1:
	kfree(req.uri);

	if (session->ses_ops.on_session_event) {
		error_event.reason = (enum xio_status)xio_errno();
		session->ses_ops.on_session_event(
				session, &error_event,
				session->cb_user_context);
	}
	return 0;
}
示例#13
0
/*---------------------------------------------------------------------------*/
int xio_on_setup_req_recv(struct xio_connection *connection,
			  struct xio_task *task)
{
	struct xio_msg			*msg = &task->imsg;
	struct xio_new_session_req	req;
	uint8_t				*ptr;
	uint16_t			len;
	struct xio_session_hdr		hdr;
	struct xio_session		*session = connection->session;
	int				retval;
	struct xio_session_event_data  error_event = {
		.conn = NULL,
		.conn_user_context = NULL,
		.event = XIO_SESSION_ERROR_EVENT,
		.reason = XIO_E_SUCCESS,
		.private_data = NULL,
		.private_data_len = 0,
	};

	/* read session header */
	xio_session_read_header(task, &hdr);
#ifdef XIO_SESSION_DEBUG
	connection->peer_connection = hdr.connection;
	connection->peer_session = hdr.session;
#endif
	task->imsg.sn = hdr.serial_num;
	task->connection = connection;
	task->session = session;
	connection->session->setup_req = msg;
	connection->session->connection_srv_first = connection;

	/* read the header */
	ptr = (uint8_t *)msg->in.header.iov_base;

	memset(&req, 0, sizeof(req));

	/* session id */
	len = xio_read_uint32(&session->peer_session_id, 0, ptr);
	ptr  = ptr + len;

	/* queue depth bytes */
	len = xio_read_uint64(&session->peer_snd_queue_depth_bytes, 0, ptr);
	ptr = ptr + len;

	len = xio_read_uint64(&session->peer_rcv_queue_depth_bytes, 0, ptr);
	ptr = ptr + len;

	/* queue depth msgs */
	len = xio_read_uint16((uint16_t *)&session->peer_snd_queue_depth_msgs,
			      0, ptr);
	ptr = ptr + len;

	len = xio_read_uint16((uint16_t *)&session->peer_rcv_queue_depth_msgs,
			      0, ptr);
	ptr = ptr + len;

	/* uri length */
	len = xio_read_uint16(&req.uri_len, 0, ptr);
	ptr = ptr + len;

	/* private length */
	len = xio_read_uint16(&req.private_data_len, 0, ptr);
	ptr = ptr + len;

	if (req.uri_len) {
		req.uri =
		  (char *)kcalloc(req.uri_len, sizeof(char), GFP_KERNEL);
		if (unlikely(!req.uri)) {
			xio_set_error(ENOMEM);
			ERROR_LOG("uri allocation failed. len:%d\n",
				  req.uri_len);
			goto cleanup1;
		}

		len = xio_read_array((uint8_t *)req.uri,
				     req.uri_len, 0, ptr);
		ptr = ptr + len;
	}
	if (req.private_data_len) {
		req.private_data = kcalloc(req.private_data_len,
					   sizeof(uint8_t), GFP_KERNEL);
		if (unlikely(!req.private_data)) {
			xio_set_error(ENOMEM);
			ERROR_LOG("private data allocation failed. len:%d\n",
				  req.private_data_len);
			goto cleanup2;
		}
		len = xio_read_array((uint8_t *)req.private_data,
				     req.private_data_len,
				     0, ptr);
		ptr = ptr + len;
	}

	req.proto = (enum xio_proto)xio_nexus_get_proto(connection->nexus);
	xio_nexus_get_peer_addr(connection->nexus,
				&req.src_addr, sizeof(req.src_addr));

	/* cache the task in io queue*/
	xio_connection_queue_io_task(connection, task);

	/* notify the upper layer */
	if (connection->ses_ops.on_new_session) {
#ifdef XIO_THREAD_SAFE_DEBUG
		xio_ctx_debug_thread_unlock(connection->ctx);
#endif
		retval = connection->ses_ops.on_new_session(
					session, &req,
					connection->cb_user_context);
#ifdef XIO_THREAD_SAFE_DEBUG
		xio_ctx_debug_thread_lock(connection->ctx);
#endif
		if (retval)
			goto cleanup2;
	} else {
		retval = xio_accept(session, NULL, 0, NULL, 0);
		if (retval) {
			ERROR_LOG("failed to auto accept session. session:%p\n",
				  session);
			goto cleanup2;
		}
	}

	/* Don't move session state to ONLINE. In case of multiple portals
	 * the accept moves the state to ACCEPTED until the first "HELLO"
	 * message arrives. Note that the "upper layer" may call redirect or
	 * reject.
	 */

	xio_session_notify_new_connection(session, connection);

	kfree(req.private_data);
	kfree(req.uri);

	return 0;

cleanup2:
	kfree(req.private_data);

cleanup1:
	kfree(req.uri);

	if (session->ses_ops.on_session_event) {
#ifdef XIO_THREAD_SAFE_DEBUG
		xio_ctx_debug_thread_unlock(connection->ctx);
#endif
		error_event.reason = (enum xio_status)xio_errno();
		session->ses_ops.on_session_event(
				session, &error_event,
				session->cb_user_context);
#ifdef XIO_THREAD_SAFE_DEBUG
		xio_ctx_debug_thread_lock(connection->ctx);
#endif
	}
	return 0;
}

/*---------------------------------------------------------------------------*/
/* xio_session_write_accept_rsp						     */
/*---------------------------------------------------------------------------*/
struct xio_msg *xio_session_write_accept_rsp(struct xio_session *session,
					     uint16_t action,
					     const char **portals_array,
					     uint16_t portals_array_len,
					     void *user_context,
					     uint16_t user_context_len)
{
	struct xio_msg		*msg;
	uint8_t			*buf;
	uint8_t			*ptr;
	uint16_t		len, i, str_len, tot_len;

	/* calculate length */
	tot_len = 5*sizeof(uint16_t) + sizeof(uint32_t) + 2*sizeof(uint64_t);
	for (i = 0; i < portals_array_len; i++)
		tot_len += strlen(portals_array[i]) + sizeof(uint16_t);
	tot_len += user_context_len;

	if (tot_len > SETUP_BUFFER_LEN)  {
		ERROR_LOG("buffer is too small\n");
		xio_set_error(EMSGSIZE);
		return NULL;
	}

	/* allocate message */
	buf = (uint8_t *)kcalloc(SETUP_BUFFER_LEN + sizeof(struct xio_msg),
		      sizeof(uint8_t), GFP_KERNEL);
	if (unlikely(!buf)) {
		ERROR_LOG("message allocation failed\n");
		xio_set_error(ENOMEM);
		return NULL;
	}

	/* fill the message */
	msg = (struct xio_msg *)buf;
	msg->out.header.iov_base = buf + sizeof(struct xio_msg);
	msg->out.header.iov_len = 0;

	ptr = (uint8_t *)msg->out.header.iov_base;
	len = 0;

	/* serialize message into the buffer */

	/* session_id */
	len = xio_write_uint32(session->session_id, 0, ptr);
	ptr  = ptr + len;

	/* action */
	len = xio_write_uint16(action, 0, ptr);
	ptr  = ptr + len;

	if (action == XIO_ACTION_ACCEPT) {
		/* tx queue depth bytes */
		len = xio_write_uint64(session->snd_queue_depth_bytes, 0, ptr);
		ptr  = ptr + len;

		/* rx queue depth bytes */
		len = xio_write_uint64(session->rcv_queue_depth_bytes, 0, ptr);
		ptr  = ptr + len;

		/* tx queue depth msgs */
		len = xio_write_uint16(session->snd_queue_depth_msgs, 0, ptr);
		ptr  = ptr + len;

		/* rx queue depth msgs */
		len = xio_write_uint16(session->rcv_queue_depth_msgs, 0, ptr);
		ptr  = ptr + len;
	}

	/* portals_array_len */
	len = xio_write_uint16(portals_array_len, 0, ptr);
	ptr  = ptr + len;

	/* user_context_len */
	len = xio_write_uint16(user_context_len, 0, ptr);
	ptr  = ptr + len;

	for (i = 0; i < portals_array_len; i++) {
		str_len = strlen(portals_array[i]);

		len = xio_write_uint16(str_len, 0, ptr);
		ptr  = ptr + len;

		len = xio_write_array((uint8_t *)portals_array[i],
				      str_len, 0, ptr);
		ptr  = ptr + len;
	}

	if (user_context_len) {
		len = xio_write_array((const uint8_t *)user_context,
				      user_context_len,
				      0, ptr);
		ptr  = ptr + len;
	}

	msg->out.header.iov_len = ptr - (uint8_t *)msg->out.header.iov_base;

	if (msg->out.header.iov_len != tot_len) {
		ERROR_LOG("calculated length %d != actual length %zd\n",
			  tot_len, msg->out.header.iov_len);
	}

	return msg;
}

/*---------------------------------------------------------------------------*/
/* xio_session_write_reject_rsp						     */
/*---------------------------------------------------------------------------*/
struct xio_msg *xio_session_write_reject_rsp(struct xio_session *session,
					     enum xio_status reason,
					     void *user_context,
					     uint16_t user_context_len)
{
	struct xio_msg	*msg;
	uint8_t			*buf;
	uint8_t			*ptr;
	uint16_t		len,  tot_len;
	uint16_t		action = XIO_ACTION_REJECT;

	/* calclate length */
	tot_len = 2*sizeof(uint16_t) + 2*sizeof(uint32_t);
	tot_len += user_context_len;

	if (tot_len > SETUP_BUFFER_LEN)  {
		ERROR_LOG("buffer is too small\n");
		xio_set_error(EMSGSIZE);
		return NULL;
	}

	/* allocate message */
	buf = (uint8_t *)kcalloc(SETUP_BUFFER_LEN + sizeof(struct xio_msg),
		      sizeof(uint8_t), GFP_KERNEL);
	if (!buf) {
		ERROR_LOG("message allocation failed\n");
		xio_set_error(ENOMEM);
		return NULL;
	}

	/* fill the message */
	msg = (struct xio_msg *)buf;
	msg->out.header.iov_base = buf + sizeof(struct xio_msg);
	msg->out.header.iov_len = 0;

	ptr = (uint8_t *)msg->out.header.iov_base;
	len = 0;

	/* serialize message into the buffer */

	/* session_id */
	len = xio_write_uint32(session->session_id, 0, ptr);
	ptr  = ptr + len;

	/* action */
	len = xio_write_uint16(action, 0, ptr);
	ptr  = ptr + len;

	/* reason */
	len = xio_write_uint32(reason, 0, ptr);
	ptr  = ptr + len;

	/* user_context_len */
	len = xio_write_uint16(user_context_len, 0, ptr);
	ptr  = ptr + len;

	if (user_context_len) {
		len = xio_write_array((const uint8_t *)user_context,
				      user_context_len,
				      0, ptr);
		ptr  = ptr + len;
	}

	msg->out.header.iov_len = ptr - (uint8_t *)msg->out.header.iov_base;

	if (msg->out.header.iov_len != tot_len) {
		ERROR_LOG("calculated length %d != actual length %zd\n",
			  tot_len, msg->out.header.iov_len);
	}

	return msg;
}

/*---------------------------------------------------------------------------*/
/* xio_accept								     */
/*---------------------------------------------------------------------------*/
int xio_accept(struct xio_session *session,
	       const char **portals_array,
	       size_t portals_array_len,
	       void *user_context,
	       size_t user_context_len)
{
	int			retval = 0;
	struct xio_msg		*msg;
	struct xio_task		*task;

	msg = xio_session_write_accept_rsp(session,
					   XIO_ACTION_ACCEPT,
					   portals_array,
					   portals_array_len,
					   user_context,
					   user_context_len);
	if (!msg) {
		ERROR_LOG("setup request creation failed\n");
		return -1;
	}

	msg->request	= session->setup_req;
	msg->type	= (enum xio_msg_type)XIO_SESSION_SETUP_RSP;

	task = container_of(msg->request,
			    struct xio_task, imsg);

	if (portals_array_len != 0) {
		/* server side state is changed to ACCEPT, will be move to
		 * ONLINE state when first "hello" message arrives
		 */
		session->state = XIO_SESSION_STATE_ACCEPTED;
		/* temporary disable teardown */
		session->disable_teardown = 1;
		TRACE_LOG("session state is now ACCEPT. session:%p\n",
			  session);
	} else {
		/* initialize credits */
		task->connection->peer_credits_msgs =
					session->peer_rcv_queue_depth_msgs;
		task->connection->credits_msgs	= 0;
		task->connection->peer_credits_bytes =
					session->peer_rcv_queue_depth_bytes;
		task->connection->credits_bytes	= 0;

		/* server side state is changed to ONLINE, immediately  */
		session->state = XIO_SESSION_STATE_ONLINE;
		TRACE_LOG("session state changed to ONLINE. session:%p\n",
			  session);
	}
	retval = xio_connection_send(task->connection, msg);
	if (retval && retval != -EAGAIN) {
		ERROR_LOG("failed to send message. errno:%d\n", -retval);
		xio_set_error(-retval);
		return -1;
	}

	return 0;
}