Imported Upstream version 2.72.alpha
[platform/upstream/glib-networking.git] / tls / tests / lossy-socket.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * Copyright (C) 2021 Ole André Vadla Ravnås <oleavr@frida.re>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * In addition, when the library is used with OpenSSL, a special
20  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
21  */
22
23 #include "config.h"
24
25 #include "lossy-socket.h"
26
27 struct _LossySocket
28 {
29   GObject parent_instance;
30
31   GDatagramBased *base_socket;
32
33   IOPredicateFunc predicate_func;
34   gpointer predicate_data;
35
36   gint next_rx_serial;
37   gint next_tx_serial;
38 };
39
40 static void lossy_socket_datagram_based_iface_init (GDatagramBasedInterface *iface);
41
42 G_DEFINE_TYPE_EXTENDED (LossySocket,
43                         lossy_socket,
44                         G_TYPE_OBJECT, 0,
45                         G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED,
46                                                lossy_socket_datagram_based_iface_init))
47
48 static gint
49 lossy_socket_receive_messages (GDatagramBased  *datagram_based,
50                                GInputMessage   *messages,
51                                guint            num_messages,
52                                gint             flags,
53                                gint64           timeout,
54                                GCancellable    *cancellable,
55                                GError         **error)
56 {
57   LossySocket *self = LOSSY_SOCKET (datagram_based);
58   gint ret;
59   gboolean skip;
60
61   do
62     {
63       IODetails d;
64
65       skip = FALSE;
66
67       ret = g_datagram_based_receive_messages (self->base_socket, messages,
68                                                num_messages, flags, timeout,
69                                                cancellable, error);
70       if (ret <= 0)
71         break;
72
73       d.direction = IO_IN;
74       d.serial = self->next_rx_serial++;
75
76       if (self->predicate_func (&d, self->predicate_data) == IO_DROP)
77         {
78           messages->bytes_received = 0;
79           messages->flags = 0;
80
81           if (timeout == 0)
82             {
83               ret = -1;
84               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
85                                    "Operation would block");
86             }
87           else
88             {
89               skip = TRUE;
90             }
91         }
92     }
93   while (skip);
94
95   return ret;
96 }
97
98 static gint
99 lossy_socket_send_messages (GDatagramBased  *datagram_based,
100                             GOutputMessage  *messages,
101                             guint            num_messages,
102                             gint             flags,
103                             gint64           timeout,
104                             GCancellable    *cancellable,
105                             GError         **error)
106 {
107   LossySocket *self = LOSSY_SOCKET (datagram_based);
108   IODetails d;
109
110   d.direction = IO_OUT;
111   d.serial = self->next_tx_serial++;
112
113   if (self->predicate_func (&d, self->predicate_data) == IO_DROP)
114     {
115       guint i, j;
116
117       for (i = 0; i < num_messages; i++)
118         {
119           GOutputMessage *m = &messages[i];
120
121           for (j = 0; j < m->num_vectors; j++)
122             m->bytes_sent += m->vectors[j].size;
123         }
124
125       return num_messages;
126     }
127
128   return g_datagram_based_send_messages (self->base_socket, messages,
129                                          num_messages, flags, timeout,
130                                          cancellable, error);
131 }
132
133 static GSource *
134 lossy_socket_create_source (GDatagramBased *datagram_based,
135                             GIOCondition    condition,
136                             GCancellable   *cancellable)
137 {
138   LossySocket *self = LOSSY_SOCKET (datagram_based);
139
140   return g_datagram_based_create_source (self->base_socket, condition,
141                                          cancellable);
142 }
143
144 static GIOCondition
145 lossy_socket_condition_check (GDatagramBased *datagram_based,
146                               GIOCondition    condition)
147 {
148   LossySocket *self = LOSSY_SOCKET (datagram_based);
149
150   return g_datagram_based_condition_check (self->base_socket, condition);
151 }
152
153 static gboolean
154 lossy_socket_condition_wait (GDatagramBased  *datagram_based,
155                              GIOCondition     condition,
156                              gint64           timeout,
157                              GCancellable    *cancellable,
158                              GError         **error)
159 {
160   LossySocket *self = LOSSY_SOCKET (datagram_based);
161
162   return g_datagram_based_condition_wait (self->base_socket, condition, timeout,
163                                           cancellable, error);
164 }
165
166 static void
167 lossy_socket_init (LossySocket *self)
168 {
169   self->next_rx_serial = 1;
170   self->next_tx_serial = 1;
171 }
172
173 static void
174 lossy_socket_dispose (GObject *object)
175 {
176   LossySocket *self = LOSSY_SOCKET (object);
177
178   g_clear_object (&self->base_socket);
179
180   G_OBJECT_CLASS (lossy_socket_parent_class)->dispose (object);
181 }
182
183 static void
184 lossy_socket_class_init (LossySocketClass *klass)
185 {
186   GObjectClass *object_class = G_OBJECT_CLASS (klass);
187
188   object_class->dispose = lossy_socket_dispose;
189 }
190
191 static void
192 lossy_socket_datagram_based_iface_init (GDatagramBasedInterface *iface)
193 {
194   iface->receive_messages = lossy_socket_receive_messages;
195   iface->send_messages = lossy_socket_send_messages;
196   iface->create_source = lossy_socket_create_source;
197   iface->condition_check = lossy_socket_condition_check;
198   iface->condition_wait = lossy_socket_condition_wait;
199 }
200
201 GDatagramBased *
202 lossy_socket_new (GDatagramBased  *base_socket,
203                   IOPredicateFunc  predicate_func,
204                   gpointer         predicate_data)
205 {
206   LossySocket *s;
207
208   s = g_object_new (LOSSY_TYPE_SOCKET, NULL);
209   s->base_socket = g_object_ref (base_socket);
210   s->predicate_func = predicate_func;
211   s->predicate_data = predicate_data;
212
213   return G_DATAGRAM_BASED (s);
214 }