udp-bsd.c 5.61 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * This file is part of the Nice GLib ICE library.
 *
 * (C) 2006, 2007 Collabora Ltd.
 *  Contact: Dafydd Harries
 * (C) 2006, 2007 Nokia Corporation. All rights reserved.
 *  Contact: Kai Vehmanen
 *
 * 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:
 *   Dafydd Harries, Collabora Ltd.
26 27
 *   Rémi Denis-Courmont, Nokia
 *   Kai Vehmanen
28 29 30 31 32 33 34 35 36 37 38
 *
 * 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.
 */
39 40

/*
41 42
 * Implementation of UDP socket interface using Berkeley sockets. (See
 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
43
 */
44 45 46
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
47

48 49
#include <arpa/inet.h>

50
#include <unistd.h>
51
#include <string.h>
52
#include <errno.h>
53
#include <fcntl.h>
54

55
#include "udp-bsd.h"
56

57
/*** NiceUDPSocket ***/
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
static int sock_recv_err (int fd)
{
#ifdef MSG_ERRQUEUE
  /* Silently dequeue any error message if any */
  struct msghdr hdr;
  int saved = errno, val;

  memset (&hdr, 0, sizeof (hdr));
  val = recvmsg (fd, &hdr, MSG_ERRQUEUE);
  errno = saved;
  return val == 0;
#else
  return 0;
#endif
}

74 75

static gint
76
socket_recv (
77
  NiceUDPSocket *sock,
78
  NiceAddress *from,
79 80 81 82
  guint len,
  gchar *buf)
{
  gint recvd;
83 84
  struct sockaddr_storage sa;
  guint from_len = sizeof (sa);
85

86
  recvd = recvfrom (sock->fileno, buf, len, 0, (struct sockaddr *) &sa,
87
      &from_len);
88 89 90 91 92
  if (recvd == -1)
  {
    sock_recv_err (sock->fileno);
    return -1;
  }
93

94
  nice_address_set_from_sockaddr (from, (struct sockaddr *)&sa);
95 96 97 98
  return recvd;
}

static gboolean
99
socket_send (
100
  NiceUDPSocket *sock,
101
  const NiceAddress *to,
102
  guint len,
103
  const gchar *buf)
104
{
105
  struct sockaddr_storage sa;
106
  ssize_t sent;
107

108
  nice_address_copy_to_sockaddr (to, (struct sockaddr *)&sa);
109

110
  do
111 112
    sent = sendto (sock->fileno, buf, len, 0, (struct sockaddr *) &sa,
                   sizeof (sa));
113 114 115
  while ((sent == -1) && sock_recv_err (sock->fileno));
  
  return sent == (ssize_t)len;
116 117 118
}

static void
119
socket_close (NiceUDPSocket *sock)
120 121 122 123
{
  close (sock->fileno);
}

124
/*** NiceUDPSocketFactory ***/
125 126

static gboolean
127
socket_factory_init_socket (
128
  G_GNUC_UNUSED
129 130
  NiceUDPSocketFactory *man,
  NiceUDPSocket *sock,
131
  NiceAddress *addr)
132
{
133
  int sockfd = -1;
134
  struct sockaddr_storage name;
135
  guint name_len = sizeof (name);
136

137
  (void)man;
138 139 140

  if (addr != NULL)
    {
141 142 143 144
      nice_address_copy_to_sockaddr(addr, (struct sockaddr *)&name);
    }
  else
    {
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
      memset (&name, 0, sizeof (name));
      name.ss_family = AF_UNSPEC;
    }

#if 0
  if ((name.ss_family == AF_INET6) || (name.ss_family == AF_UNSPEC))
    {
      sockfd = socket (PF_INET6, SOCK_DGRAM, 0);
      if (sockfd != -1)
        {
          int v6 = name.ss_family == AF_INET6;

#if defined (IPV6_V6ONLY)
          if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &v6, sizeof (v6)))
#else
          if (!v6)
#endif
            {
              close (sockfd);
              sockfd = -1;
            }
          else
            {
# ifdef IPV6_RECVERR
              int yes = 1;
              setsockopt (sockfd, SOL_IPV6, IPV6_RECVERR, &yes, sizeof (yes));
# endif
              name.ss_family = AF_INET6;
# ifdef HAVE_SA_LEN
              name.ss_len = sizeof (struct sockaddr_in6);
# endif
            }
        }
    }
#endif
  if ((sockfd == -1)
   && ((name.ss_family == AF_UNSPEC) || (name.ss_family == AF_INET)))
    {
      sockfd = socket (PF_INET, SOCK_DGRAM, 0);
      name.ss_family = AF_INET;
185
#ifdef HAVE_SA_LEN
186
      name.ss_len = sizeof (struct sockaddr_in);
187
#endif
188
    }
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

  if (sockfd == -1)
    return FALSE;
#ifdef IP_RECVERR
  else
    {
      int yes = 1;
      setsockopt (sockfd, SOL_IP, IP_RECVERR, &yes, sizeof (yes));
    }
#endif

#ifdef FD_CLOEXEC
  fcntl (sockfd, F_SETFD, fcntl (sockfd, F_GETFD) | FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
  fcntl (sockfd, F_SETFL, fcntl (sockfd, F_GETFL) | O_NONBLOCK);
#endif
206

207
  if(bind (sockfd, (struct sockaddr *) &name, sizeof (name)) != 0)
208 209 210 211 212
    {
      close (sockfd);
      return FALSE;
    }

213 214 215 216 217 218
  if (getsockname (sockfd, (struct sockaddr *) &name, &name_len) != 0)
    {
      close (sockfd);
      return FALSE;
    }

219
  nice_address_set_from_sockaddr (&sock->addr, (struct sockaddr *)&name);
220

221
  sock->fileno = sockfd;
222 223 224
  sock->send = socket_send;
  sock->recv = socket_recv;
  sock->close = socket_close;
225 226 227
  return TRUE;
}

228
static void
229 230 231
socket_factory_close (
  G_GNUC_UNUSED
  NiceUDPSocketFactory *man)
232
{
233
  (void)man;
234 235
}

236
NICEAPI_EXPORT void
237 238 239
nice_udp_bsd_socket_factory_init (
  G_GNUC_UNUSED
  NiceUDPSocketFactory *man)
240
{
241 242
  man->init = socket_factory_init_socket;
  man->close = socket_factory_close;
243 244
}