udp-bsd.c 5.05 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 <string.h>
50
#include <errno.h>
51
#include <fcntl.h>
52

53
#include "udp-bsd.h"
54

55
56
57
58
59
60
#ifdef G_OS_WIN32
typedef unsigned long ssize_t;
#else
#include <unistd.h>
#endif

61

62
63
64
65
66
67
static void socket_close (NiceSocket *sock);
static gint socket_recv (NiceSocket *sock, NiceAddress *from,
    guint len, gchar *buf);
static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
    guint len, const gchar *buf);
static gboolean socket_is_reliable (NiceSocket *sock);
68

69
70
NiceSocket *
nice_udp_bsd_socket_new (NiceAddress *addr)
71
{
72
  int sockfd = -1;
73
  struct sockaddr_storage name;
74
  socklen_t name_len = sizeof (name);
75
  NiceSocket *sock = g_slice_new0 (NiceSocket);
76

77
78
79
  if (!sock) {
    return NULL;
  }
80

81
82
83
84
85
86
  if (addr != NULL) {
    nice_address_copy_to_sockaddr(addr, (struct sockaddr *)&name);
  } else {
    memset (&name, 0, sizeof (name));
    name.ss_family = AF_UNSPEC;
  }
87

88
89
90
  if (name.ss_family == AF_UNSPEC || name.ss_family == AF_INET) {
    sockfd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    name.ss_family = AF_INET;
91
#ifdef HAVE_SA_LEN
92
    name.ss_len = sizeof (struct sockaddr_in);
93
#endif
94
  }
95

96
97
98
99
100
  if (sockfd == -1) {
    g_slice_free (NiceSocket, sock);
    return NULL;
  }

101
102
103
104
105
106
#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
107

108
109
110
  if(bind (sockfd, (struct sockaddr *) &name,
          name.ss_family == AF_INET? sizeof (struct sockaddr_in) :
          sizeof(struct sockaddr_in6)) < 0) {
111
    g_slice_free (NiceSocket, sock);
112
#ifdef G_OS_WIN32
113
    closesocket(sockfd);
114
#else
115
    close (sockfd);
116
#endif
117
118
    return NULL;
  }
119

120
121
122
  name_len = name.ss_family == AF_INET? sizeof (struct sockaddr_in) :
      sizeof(struct sockaddr_in6);
  if (getsockname (sockfd, (struct sockaddr *) &name, &name_len) < 0) {
123
    g_slice_free (NiceSocket, sock);
124
#ifdef G_OS_WIN32
125
    closesocket(sockfd);
126
#else
127
    close (sockfd);
128
#endif
129
130
    return NULL;
  }
131

132
  nice_address_set_from_sockaddr (&sock->addr, (struct sockaddr *)&name);
133
  sock->fileno = sockfd;
134

135
136
  sock->send = socket_send;
  sock->recv = socket_recv;
137
  sock->is_reliable = socket_is_reliable;
138
  sock->close = socket_close;
139

140
  return sock;
141
}
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

static void
socket_close (NiceSocket *sock)
{
#ifdef G_OS_WIN32
  closesocket(sock->fileno);
#else
  close (sock->fileno);
#endif
}

static gint
socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
{
  gint recvd;
  struct sockaddr_storage sa;
  socklen_t from_len = sizeof (sa);

  recvd = recvfrom (sock->fileno, buf, len, 0, (struct sockaddr *) &sa,
      &from_len);

163
164
165
166
167
168
169
170
171
  if (recvd < 0) {
#ifdef G_OS_WIN32
    if (WSAGetLastError () == WSAEWOULDBLOCK)
#else
    if (errno == EAGAIN || errno == EWOULDBLOCK)
#endif
      return 0;
  }

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  if (recvd > 0)
    nice_address_set_from_sockaddr (from, (struct sockaddr *)&sa);

  return recvd;
}

static gboolean
socket_send (NiceSocket *sock, const NiceAddress *to,
    guint len, const gchar *buf)
{
  struct sockaddr_storage sa;
  ssize_t sent;

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

  sent = sendto (sock->fileno, buf, len, 0, (struct sockaddr *) &sa,
      sa.ss_family == AF_INET? sizeof (struct sockaddr_in) :
      sizeof(struct sockaddr_in6));

  return sent == (ssize_t)len;
}

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