OBS: updates for Ubuntu 16.04
[siplcs.git] / src / purple / purple-network.c
blob5a4dd1799901a266402bdb5601081f1de70ed017
1 /**
2 * @file purple-network.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2015 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #ifdef HAVE_CONFIG_H
24 #include "config.h" /* coverity[hfa: FALSE] */
25 #endif
27 #include <string.h>
29 #include "glib.h"
31 #include "conversation.h"
32 #include "network.h"
33 #include "eventloop.h"
35 #ifdef _WIN32
36 /* wrappers for write() & friends for socket handling */
37 #include "win32/win32dep.h"
38 #include <nspapi.h>
39 #else
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <net/if.h>
45 #include <arpa/inet.h>
46 #ifdef HAVE_SYS_SOCKIO_H
47 #include <sys/sockio.h> /* SIOCGIFCONF for Solaris */
48 #endif
49 #endif
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
55 #include "sipe-common.h"
56 #include "sipe-backend.h"
57 #include "purple-private.h"
59 #if 0
60 /**
61 * @TODO: get_suitable_local_ip()
63 * The code is most likely broken for Mac OS X as it seems that that platform
64 * returns variable-sized "struct ifreq". The new, alignment compliant code
65 * assumes a fix-sized "struct ifreq", i.e. it uses array access.
67 * If somebody is bothered by this, please provide a *VERIFIED* alternative
68 * implementation for platforms that define _SIZEOF_ADDR_IFREQ().
70 **/
73 * Calling sizeof(struct ifreq) isn't always correct on
74 * Mac OS X (and maybe others).
76 #ifdef _SIZEOF_ADDR_IFREQ
77 # define HX_SIZE_OF_IFREQ(a) _SIZEOF_ADDR_IFREQ(a)
78 #else
79 # define HX_SIZE_OF_IFREQ(a) sizeof(a)
80 #endif
81 #endif
83 #define IFREQ_MAX 32
85 /**
86 * Returns local IP address suitable for connection.
88 * purple_network_get_my_ip() will not do this, because it might return an
89 * address within 169.254.x.x range that was assigned to interface disconnected
90 * from the network (when multiple network adapters are available). This is a
91 * copy-paste from libpurple's network.c, only change is that link local addresses
92 * are ignored.
94 * Maybe this should be fixed in libpurple or some better solution found.
96 static const gchar *get_suitable_local_ip(void)
98 int source = socket(PF_INET,SOCK_STREAM, 0);
100 if (source >= 0) {
101 struct ifreq *buffer = g_new0(struct ifreq, IFREQ_MAX);
102 struct ifconf ifc;
103 guint32 lhost = htonl(127 * 256 * 256 * 256 + 1);
104 guint32 llocal = htonl((169 << 24) + (254 << 16));
105 guint i;
106 static char ip[16];
108 /* @TODO: assumes constant sizeof(struct ifreq) [see above] */
109 ifc.ifc_len = sizeof(struct ifreq) * IFREQ_MAX;
110 ifc.ifc_req = buffer;
111 ioctl(source, SIOCGIFCONF, &ifc);
113 close(source);
115 for (i = 0; i < IFREQ_MAX; i++)
117 /* @TODO: assumes constant sizeof(struct ifreq) [see above] */
118 struct ifreq *ifr = &buffer[i];
120 if (ifr->ifr_addr.sa_family == AF_INET)
122 struct sockaddr_in sin;
123 memcpy(&sin, &ifr->ifr_addr, sizeof(struct sockaddr_in));
124 if (sin.sin_addr.s_addr != lhost
125 && (sin.sin_addr.s_addr & htonl(0xFFFF0000)) != llocal)
127 long unsigned int add = ntohl(sin.sin_addr.s_addr);
128 g_snprintf(ip, 16, "%lu.%lu.%lu.%lu",
129 ((add >> 24) & 255),
130 ((add >> 16) & 255),
131 ((add >> 8) & 255),
132 add & 255);
134 g_free(buffer);
135 return ip;
139 g_free(buffer);
142 return "0.0.0.0";
145 const gchar *sipe_backend_network_ip_address(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public)
147 const gchar *ip = purple_network_get_my_ip(-1);
148 if (g_str_has_prefix(ip, "169.254."))
149 ip = get_suitable_local_ip();
150 return ip;
153 struct sipe_backend_listendata {
154 sipe_listen_start_cb listen_cb;
155 sipe_client_connected_cb connect_cb;
157 PurpleNetworkListenData *listener;
158 int watcher;
160 int listenfd;
161 gpointer data;
164 static void
165 client_connected_cb(struct sipe_backend_listendata *ldata, gint listenfd,
166 SIPE_UNUSED_PARAMETER PurpleInputCondition cond)
168 struct sockaddr_in saddr;
169 socklen_t slen = sizeof (saddr);
171 int fd = accept(listenfd, (struct sockaddr*)&saddr, &slen);
173 purple_input_remove(ldata->watcher);
174 ldata->watcher = 0;
175 close(listenfd);
176 ldata->listenfd = -1;
178 if (ldata->connect_cb) {
179 ldata->connect_cb(sipe_backend_fd_from_int(fd), ldata->data);
182 g_free(ldata);
185 static void
186 backend_listen_cb(int listenfd, struct sipe_backend_listendata *ldata)
188 struct sockaddr_in addr;
189 socklen_t socklen = sizeof (addr);
191 ldata->listenfd = -1;
192 ldata->listener = NULL;
193 ldata->listenfd = listenfd;
195 /* ignore error code */
196 (void) getsockname(listenfd, (struct sockaddr*)&addr, &socklen);
197 if (ldata->listen_cb)
198 ldata->listen_cb(ntohs(addr.sin_port), ldata->data);
200 ldata->watcher = purple_input_add(listenfd, PURPLE_INPUT_READ,
201 (PurpleInputFunction)client_connected_cb,
202 ldata);
205 struct sipe_backend_listendata *
206 sipe_backend_network_listen_range(unsigned short port_min,
207 unsigned short port_max,
208 sipe_listen_start_cb listen_cb,
209 sipe_client_connected_cb connect_cb,
210 gpointer data)
212 struct sipe_backend_listendata *ldata;
213 ldata = g_new0(struct sipe_backend_listendata, 1);
215 ldata->listen_cb = listen_cb;
216 ldata->connect_cb = connect_cb;
217 ldata->data = data;
218 ldata->listener = purple_network_listen_range(port_min, port_max,
219 #if PURPLE_VERSION_CHECK(3,0,0)
220 /* @TODO: does FT work with IPv6? */
221 AF_INET,
222 #endif
223 SOCK_STREAM,
224 #if PURPLE_VERSION_CHECK(3,0,0)
225 /* @TODO: should we allow external mapping? */
226 FALSE,
227 #endif
228 (PurpleNetworkListenCallback)backend_listen_cb,
229 ldata);
231 if (!ldata->listener) {
232 g_free(ldata);
233 return NULL;
236 return ldata;
239 void sipe_backend_network_listen_cancel(struct sipe_backend_listendata *ldata)
241 g_return_if_fail(ldata);
243 if (ldata->listener)
244 purple_network_listen_cancel(ldata->listener);
245 if (ldata->listenfd)
246 close(ldata->listenfd);
247 g_free(ldata);
250 struct sipe_backend_fd *
251 sipe_backend_fd_from_int(int fd)
253 struct sipe_backend_fd *sipe_fd = g_new(struct sipe_backend_fd, 1);
254 sipe_fd->fd = fd;
255 return sipe_fd;
258 gboolean
259 sipe_backend_fd_is_valid(struct sipe_backend_fd *fd)
261 return fd && fd->fd >= 0;
264 void
265 sipe_backend_fd_free(struct sipe_backend_fd *fd)
267 g_free(fd);
271 Local Variables:
272 mode: c
273 c-file-style: "bsd"
274 indent-tabs-mode: t
275 tab-width: 8
276 End: