static gboolean socket_send (NiceSocket *sock, const NiceAddress *to, guint len, const gchar *buf) { PseudoSSLPriv *priv = sock->priv; if (priv->handshaken) { if (priv->base_socket) return nice_socket_send (priv->base_socket, to, len, buf); else return FALSE; } else { add_to_be_sent (sock, to, buf, len); } return TRUE; }
static gboolean socket_send_more ( GSocket *gsocket, GIOCondition condition, gpointer data) { NiceSocket *sock = (NiceSocket *) data; TcpPriv *priv = sock->priv; struct to_be_sent *tbs = NULL; GError *gerr = NULL; agent_lock (); if (g_source_is_destroyed (g_main_current_source ())) { nice_debug ("Source was destroyed. " "Avoided race condition in tcp-bsd.c:socket_send_more"); agent_unlock (); return FALSE; } while ((tbs = g_queue_pop_head (&priv->send_queue)) != NULL) { int ret; if(condition & G_IO_HUP) { /* connection hangs up */ ret = -1; } else { GOutputVector local_bufs = { tbs->buf, tbs->length }; ret = g_socket_send_message (sock->fileno, NULL, &local_bufs, 1, NULL, 0, G_SOCKET_MSG_NONE, NULL, &gerr); } if (ret < 0) { if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { GOutputVector local_buf = { tbs->buf, tbs->length }; NiceOutputMessage local_message = {&local_buf, 1}; add_to_be_sent (sock, &local_message, 0, local_buf.size, TRUE); free_to_be_sent (tbs); g_error_free (gerr); break; } g_clear_error (&gerr); } else if (ret < (int) tbs->length) { GOutputVector local_buf = { tbs->buf + ret, tbs->length - ret }; NiceOutputMessage local_message = {&local_buf, 1}; add_to_be_sent (sock, &local_message, 0, local_buf.size, TRUE); free_to_be_sent (tbs); break; } free_to_be_sent (tbs); } if (g_queue_is_empty (&priv->send_queue)) { g_source_destroy (priv->io_source); g_source_unref (priv->io_source); priv->io_source = NULL; agent_unlock (); return FALSE; } agent_unlock (); return TRUE; }
static gssize socket_send_message (NiceSocket *sock, const NiceOutputMessage *message) { TcpPriv *priv = sock->priv; gssize ret; GError *gerr = NULL; gsize message_len; /* Don't try to access the socket if it had an error, otherwise we risk a * crash with SIGPIPE (Broken pipe) */ if (priv->error) return -1; message_len = output_message_get_size (message); /* First try to send the data, don't send it later if it can be sent now * this way we avoid allocating memory on every send */ if (g_queue_is_empty (&priv->send_queue)) { ret = g_socket_send_message (sock->fileno, NULL, message->buffers, message->n_buffers, NULL, 0, G_SOCKET_MSG_NONE, NULL, &gerr); if (ret < 0) { if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) || g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_FAILED)) { /* Queue the message and send it later. */ add_to_be_sent (sock, message, 0, message_len, FALSE); ret = message_len; } g_error_free (gerr); } else if ((gsize) ret < message_len) { /* Partial send. */ add_to_be_sent (sock, message, ret, message_len, TRUE); ret = message_len; } } else { /* FIXME: This dropping will break http/socks5/etc * We probably need a way to the upper layer to control reliability */ /* If the queue is too long, drop whatever packets we can. */ if (g_queue_get_length (&priv->send_queue) >= MAX_QUEUE_LENGTH) { guint peek_idx = 0; struct to_be_sent *tbs = NULL; while ((tbs = g_queue_peek_nth (&priv->send_queue, peek_idx)) != NULL) { if (tbs->can_drop) { tbs = g_queue_pop_nth (&priv->send_queue, peek_idx); free_to_be_sent (tbs); break; } else { peek_idx++; } } } /* Queue the message and send it later. */ add_to_be_sent (sock, message, 0, message_len, FALSE); ret = message_len; } return ret; }