+static void handle_client_tcp_connect(struct client *server)
+{
+ g_return_if_fail(server!=NULL);
+ g_return_if_fail(server->connect_pending);
+ g_return_if_fail(master_tcp!=NULL);
+
+ errno=0;
+ if (connect(
+ server->gpollfd.fd, /* sockfd */
+ (struct sockaddr *)&sockaddr_in_server, /* to */
+ sizeof(sockaddr_in_server))) { /* tolen */
+ g_warning(_("Error establishing server TCP connection: %m"));
+ client_destroy(server);
+ return;
+ }
+ g_assert(server->connect_pending);
+ server->connect_pending=0;
+}
+
+/* Read from client->gpollfd.fd the data for client->bound->gstring_to_send. */
+static void handle_client_tcp_read(struct client *client)
+{
+ g_return_if_fail(client!=NULL);
+ g_return_if_fail(client->bound!=NULL);
+ g_return_if_fail(!client->connect_pending);
+ g_return_if_fail(master_tcp!=NULL);
+
+ for (;;) {
+ssize_t gotlen;
+size_t read_max;
+char buf[GSTRING_TO_SEND_MAX];
+
+ read_max=sizeof(buf)-client->bound->gstring_to_send->len;
+ g_assert(read_max>=0);
+ if (read_max<=0) /* In fact it initially should not happen, there would be no: G_IO_IN */
+ break;
+ gotlen=read(client->gpollfd.fd,buf,read_max);
+ if (gotlen==-1) {
+ if (errno==EAGAIN)
+ break;
+ g_warning(_("Error reading data from %s"),SOCKADDR_IN_TO_STRING(&client->sockaddr_in_from));
+ client_destroy(client);
+ return;
+ }
+ if (gotlen==0) {
+ /* Successful close; leave the bound peer's 'gstring_to_send' to be written there. */
+ if (client->server_only && client->bound->gstring_to_send->len)
+ client_split(client);
+ client_destroy(client);
+ return;
+ }
+ g_assert(gotlen>0);
+ g_assert((size_t)gotlen<=read_max);
+ g_string_append_len(client->bound->gstring_to_send,buf,gotlen);
+ }
+}
+
+/* Write to client->gpollfd.fd the data from client->gstring_to_send. */
+static void handle_client_tcp_write(struct client *client)
+{
+ g_return_if_fail(client!=NULL);
+ g_return_if_fail(!client->connect_pending);
+ g_return_if_fail(master_tcp!=NULL);
+
+ for (;;) {
+ssize_t gotlen;
+
+ if (client->gstring_to_send->len<=0) /* In fact it initially should not happen, there would be no: G_IO_OUT */
+ break;
+ gotlen=write(client->gpollfd.fd,client->gstring_to_send->str,client->gstring_to_send->len);
+ if (gotlen==-1) {
+ if (errno==EAGAIN)
+ break;
+ g_warning(_("Error writing data to %s"),SOCKADDR_IN_TO_STRING(&client->sockaddr_in_from));
+ client_destroy(client);
+ return;
+ }
+ if (gotlen<=0)
+ break;
+ g_assert((size_t)gotlen<=client->gstring_to_send->len);
+ g_string_erase(client->gstring_to_send,0,gotlen);
+ }
+
+ /* Nothing left to do for such client. */
+ if (!client->gstring_to_send->len && !client->bound)
+ client_destroy(client);
+}
+