pseudossl.c 7.59 KB
Newer Older
1
2
3
/*
 * This file is part of the Nice GLib ICE library.
 *
4
5
6
 * (C) 2008-2009 Collabora Ltd.
 *  Contact: Youness Alaoui
 * (C) 2008-2009 Nokia Corporation. All rights reserved.
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Nice GLib ICE library.
 *
 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
 * Corporation. All Rights Reserved.
 *
 * Contributors:
24
 *   Youness Alaoui, Collabora Ltd.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
 * case the provisions of LGPL are applicable instead of those above. If you
 * wish to allow use of your version of this file only under the terms of the
 * LGPL and not to allow others to use your version of this file under the
 * MPL, indicate your decision by deleting the provisions above and replace
 * them with the notice and other provisions required by the LGPL. If you do
 * not delete the provisions above, a recipient may use your version of this
 * file under either the MPL or the LGPL.
 */

/*
 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "pseudossl.h"

#include <string.h>

#ifndef G_OS_WIN32
#include <unistd.h>
#endif

typedef struct {
  gboolean handshaken;
  NiceSocket *base_socket;
  GQueue send_queue;
} PseudoSSLPriv;


struct to_be_sent {
61
62
  guint8 *buf;  /* owned */
  gsize length;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  NiceAddress to;
};


static const gchar SSL_SERVER_HANDSHAKE[] = {
  0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
  0x46, 0x03, 0x01, 0x42, 0x85, 0x45, 0xa7, 0x27,
  0xa9, 0x5d, 0xa0, 0xb3, 0xc5, 0xe7, 0x53, 0xda,
  0x48, 0x2b, 0x3f, 0xc6, 0x5a, 0xca, 0x89, 0xc1,
  0x58, 0x52, 0xa1, 0x78, 0x3c, 0x5b, 0x17, 0x46,
  0x00, 0x85, 0x3f, 0x20, 0x0e, 0xd3, 0x06, 0x72,
  0x5b, 0x5b, 0x1b, 0x5f, 0x15, 0xac, 0x13, 0xf9,
  0x88, 0x53, 0x9d, 0x9b, 0xe8, 0x3d, 0x7b, 0x0c,
  0x30, 0x32, 0x6e, 0x38, 0x4d, 0xa2, 0x75, 0x57,
  0x41, 0x6c, 0x34, 0x5c, 0x00, 0x04, 0x00};

static const gchar SSL_CLIENT_HANDSHAKE[] = {
  0x80, 0x46, 0x01, 0x03, 0x01, 0x00, 0x2d, 0x00,
  0x00, 0x00, 0x10, 0x01, 0x00, 0x80, 0x03, 0x00,
  0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x40, 0x02,
  0x00, 0x80, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04,
  0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, 0x00, 0xfe,
  0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, 0x00,
  0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06,
  0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc,
  0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea};


static void socket_close (NiceSocket *sock);
92
93
static gint socket_recv_messages (NiceSocket *sock,
    NiceInputMessage *recv_messages, guint n_recv_messages);
94
95
static gint socket_send_messages (NiceSocket *sock,
    const NiceOutputMessage *messages, guint n_messages);
96
97
static gboolean socket_is_reliable (NiceSocket *sock);

98
99
static void add_to_be_sent (NiceSocket *sock, const NiceOutputMessage *messages,
    guint n_messages);
100
static void free_to_be_sent (struct to_be_sent *tbs);
101
102
103


NiceSocket *
104
nice_pseudossl_socket_new (NiceSocket *base_socket)
105
106
107
108
109
110
111
112
113
114
{
  PseudoSSLPriv *priv;
  NiceSocket *sock = g_slice_new0 (NiceSocket);
  sock->priv = priv = g_slice_new0 (PseudoSSLPriv);

  priv->handshaken = FALSE;
  priv->base_socket = base_socket;

  sock->fileno = priv->base_socket->fileno;
  sock->addr = priv->base_socket->addr;
115
  sock->send_messages = socket_send_messages;
116
  sock->recv_messages = socket_recv_messages;
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  sock->is_reliable = socket_is_reliable;
  sock->close = socket_close;

  /* We send 'to' NULL because it will always be to an already connected
   * TCP base socket, which ignores the destination */
  nice_socket_send (priv->base_socket, NULL,
      sizeof(SSL_CLIENT_HANDSHAKE), SSL_CLIENT_HANDSHAKE);

  return sock;
}


static void
socket_close (NiceSocket *sock)
{
  PseudoSSLPriv *priv = sock->priv;

  if (priv->base_socket)
    nice_socket_free (priv->base_socket);

137
138
139
  g_queue_foreach (&priv->send_queue, (GFunc) free_to_be_sent, NULL);
  g_queue_clear (&priv->send_queue);

140
141
142
143
144
  g_slice_free(PseudoSSLPriv, sock->priv);
}


static gint
145
146
socket_recv_messages (NiceSocket *sock,
    NiceInputMessage *recv_messages, guint n_recv_messages)
147
148
149
150
{
  PseudoSSLPriv *priv = sock->priv;

  if (priv->handshaken) {
151
152
153
154
155
156
    if (priv->base_socket) {
      /* Fast path: once we’ve done the handshake, pass straight through to the
       * base socket. */
      return nice_socket_recv_messages (priv->base_socket,
          recv_messages, n_recv_messages);
    }
157
  } else {
158
159
160
161
    guint8 data[sizeof(SSL_SERVER_HANDSHAKE)];
    gint ret = -1;
    GInputVector local_recv_buf = { data, sizeof (data) };
    NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
162

163
164
165
166
    if (priv->base_socket) {
      ret = nice_socket_recv_messages (priv->base_socket,
          &local_recv_message, 1);
    }
167
168
169

    if (ret <= 0) {
      return ret;
170
171
    } else if (ret == 1 &&
        local_recv_buf.size == sizeof (SSL_SERVER_HANDSHAKE) &&
172
173
        memcmp(SSL_SERVER_HANDSHAKE, data, sizeof(SSL_SERVER_HANDSHAKE)) == 0) {
      struct to_be_sent *tbs = NULL;
174
      priv->handshaken = TRUE;
175
      while ((tbs = g_queue_pop_head (&priv->send_queue))) {
176
177
        nice_socket_send (priv->base_socket, &tbs->to, tbs->length,
            (const gchar *) tbs->buf);
178
179
180
181
182
183
184
185
        g_free (tbs->buf);
        g_slice_free (struct to_be_sent, tbs);
      }
    } else {
      if (priv->base_socket)
        nice_socket_free (priv->base_socket);
      priv->base_socket = NULL;

186
      return -1;
187
188
189
190
191
    }
  }
  return 0;
}

192
193
194
static gint
socket_send_messages (NiceSocket *sock, const NiceOutputMessage *messages,
    guint n_messages)
195
196
197
198
{
  PseudoSSLPriv *priv = sock->priv;

  if (priv->handshaken) {
199
200
201
    /* Fast path: pass directly through to the base socket once the handshake is
     * complete. */
    if (priv->base_socket == NULL)
202
      return FALSE;
203
204

    return nice_socket_send_messages (priv->base_socket, messages, n_messages);
205
  } else {
206
    add_to_be_sent (sock, messages, n_messages);
207
208
209
210
211
212
213
214
215
216
217
218
219
  }
  return TRUE;
}


static gboolean
socket_is_reliable (NiceSocket *sock)
{
  return TRUE;
}


static void
220
221
add_to_be_sent (NiceSocket *sock, const NiceOutputMessage *messages,
    guint n_messages)
222
223
{
  PseudoSSLPriv *priv = sock->priv;
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  guint i;

  for (i = 0; i < n_messages; i++) {
    struct to_be_sent *tbs;
    const NiceOutputMessage *message = &messages[i];
    guint j;
    gsize offset = 0;

    tbs = g_slice_new0 (struct to_be_sent);

    /* Compact the buffer. */
    tbs->buf = g_malloc (message->length);
    tbs->length = message->length;
    if (message->to != NULL)
      tbs->to = *message->to;
    g_queue_push_tail (&priv->send_queue, tbs);

    for (j = 0;
         (message->n_buffers >= 0 && j < (guint) message->n_buffers) ||
         (message->n_buffers < 0 && message->buffers[j].buffer != NULL);
         j++) {
      const GOutputVector *buffer = &message->buffers[j];
      gsize len;

      len = MIN (message->length - offset, buffer->size);
      memcpy (tbs->buf + offset, buffer->buffer, len);
      offset += len;
    }
252

253
254
    g_assert_cmpuint (offset, ==, message->length);
  }
255
}
256
257
258
259
260
261
262

static void
free_to_be_sent (struct to_be_sent *tbs)
{
  g_free (tbs->buf);
  g_slice_free (struct to_be_sent, tbs);
}