1、发送网络数据包
1.1、spice_channel_write函数:往通道中写数据
/* coroutine context */
static void spice_channel_write(SpiceChannel *channel, const void *data, size_t len)
{
#ifdef HAVE_SASL
if (channel->priv->sasl_conn) {
spice_channel_flush_sasl(channel, data, len);
return;
}
#endif
spice_channel_flush_wire(channel, data, len);
}
1.2、spice_channel_flush_wire函数:实现循环写入网络中
//将data指针的datalen长度的数据放到wire中
static void spice_channel_flush_wire(SpiceChannel *channel,
const void *data,
size_t datalen)
{
SpiceChannelPrivate *c = channel->priv;
const char *ptr = data;
size_t offset = 0;
GIOCondition cond;
while (offset < datalen) {
gssize ret;
if (c->has_error) return;
ret = spice_channel_flush_wire_nonblocking(channel, ptr+offset, datalen-offset, &cond);
if (ret == -1) {
if (cond != 0) {
// TODO: should use g_pollable_input/output_stream_create_source() in 2.28 ?
g_coroutine_socket_wait(&c->coroutine, c->sock, cond);
continue;
} else {
CHANNEL_DEBUG(channel, "Closing the channel: spice_channel_flush %d", errno);
c->has_error = TRUE;
return;
}
}
if (ret == 0) {
CHANNEL_DEBUG(channel, "Closing the connection: spice_channel_flush");
c->has_error = TRUE;
return;
}
offset += ret;
}
}
1.3、spice_channel_flush_wire_nonblocking函数:处理xxx_flush_wire()函数的非阻塞部分,它返回写入结果,并将在@cond中设置适当的位,以防写入函数阻塞。
static gint spice_channel_flush_wire_nonblocking(SpiceChannel *channel,
const gchar *ptr,
size_t len,
GIOCondition *cond)
{
SpiceChannelPrivate *c = channel->priv;
gssize ret;
g_assert(cond != NULL);
*cond = 0;
if (c->tls) {
ret = SSL_write(c->ssl, ptr, len);
if (ret < 0) {
ret = SSL_get_error(c->ssl, ret);
*cond = ssl_error_to_cond(ret);
ret = -1;
}
} else {
GError *error = NULL;
ret = g_pollable_output_stream_write_nonblocking(G_POLLABLE_OUTPUT_STREAM(c->out), ptr, len, NULL, &error);
if (ret < 0) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
*cond = G_IO_OUT;
} else {
CHANNEL_DEBUG(channel, "Send error %s", error->message);
}
g_clear_error(&error);
ret = -1;
}
}
return ret;
}
2、接收网络数据包
2.1、spice_channel_read函数:提供给外部调用,将通道中传输的数据读出来到data中,长度值为“len”字节的数据填充“data”缓冲区。如果连接关闭或出现未知错误,则返回0;如果错误,则小于0;如果成功,则返回长度
/*
* Fill the 'data' buffer up with exactly 'len' bytes worth of data
* Returns 0 if connection was closed or on unknown errors, <0 for error and
* length on success
*/
/* coroutine context */
static int spice_channel_read(SpiceChannel *channel, void *data, size_t length)
{
SpiceChannelPrivate *c = channel->priv;
gsize len = length;
int ret;
while (len > 0) {
if (c->has_error) return 0; /* has_error is set by disconnect(), return no error */
#ifdef HAVE_SASL
if (c->sasl_conn)
ret = spice_channel_read_sasl(channel, data, len);
else
#endif
ret = spice_channel_read_wire(channel, data, len);
if (ret < 0)
return ret;
g_assert(ret <= len);
len -= ret;
data = ((char*)data) + ret;
#if DEBUG
if (len > 0)
CHANNEL_DEBUG(channel, "still needs %" G_GSIZE_FORMAT, len);
#endif
}
c->total_read_bytes += length;
return length;
}
2.2、spice_channel_read_wire函数:cond信号读取数据,将数据放到data中,长度放到len
/*
* Read at least 1 more byte of data straight off the wire
* into the requested buffer.
*/
/* coroutine context */
static int spice_channel_read_wire(SpiceChannel *channel, void *data, size_t len)
{
SpiceChannelPrivate *c = channel->priv;
while (TRUE) {
gssize ret;
GIOCondition cond;
if (c->has_error) {
/* has_error is set by disconnect(), return no error */
return 0;
}
ret = spice_channel_read_wire_nonblocking(channel, data, len, &cond);
if (ret == -1) {
if (cond != 0) {
// TODO: should use g_pollable_input/output_stream_create_source() ?
g_coroutine_socket_wait(&c->coroutine, c->sock, cond);
continue;
} else {
c->has_error = TRUE;
return errno > 0 ? -errno : -EIO;
}
}
if (ret == 0) {
CHANNEL_DEBUG(channel, "Closing the connection: spice_channel_read() - ret=0");
c->has_error = TRUE;
return 0;
}
return ret;
}
}
2.3、spice_channel_read_wire_nonblocking函数:poll方式读取数据
static int spice_channel_read_wire_nonblocking(SpiceChannel *channel,
void *data,
size_t len,
GIOCondition *cond)
{
SpiceChannelPrivate *c = channel->priv;
gssize ret;
g_assert(cond != NULL);
*cond = 0;
if (c->tls) {
ret = SSL_read(c->ssl, data, len);
if (ret < 0) {
ret = SSL_get_error(c->ssl, ret);
*cond = ssl_error_to_cond(ret);
ret = -1;
}
} else {
GError *error = NULL;
ret = g_pollable_input_stream_read_nonblocking(G_POLLABLE_INPUT_STREAM(c->in),
data, len, NULL, &error);
if (ret < 0) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
*cond = G_IO_IN;
} else {
CHANNEL_DEBUG(channel, "Read error %s", error->message);
}
g_clear_error(&error);
ret = -1;
}
}
return ret;
}