OBS: update support for CentOS & Scientific Linux 7
[siplcs.git] / src / purple / purple-network.c
blobce6f4af4b38fec15c59ecd7273ba5480f69c83f3
1 /**
2 * @file purple-network.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2018 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/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
50 #include "sipe-common.h"
51 #include "sipe-backend.h"
52 #include "purple-private.h"
54 struct sipe_backend_listendata {
55 sipe_listen_start_cb listen_cb;
56 sipe_client_connected_cb connect_cb;
58 PurpleNetworkListenData *listener;
59 int watcher;
61 int listenfd;
62 gpointer data;
65 static void
66 client_connected_cb(struct sipe_backend_listendata *ldata, gint listenfd,
67 SIPE_UNUSED_PARAMETER PurpleInputCondition cond)
69 struct sockaddr_in saddr;
70 socklen_t slen = sizeof (saddr);
72 int fd = accept(listenfd, (struct sockaddr*)&saddr, &slen);
74 purple_input_remove(ldata->watcher);
75 ldata->watcher = 0;
76 close(listenfd);
77 ldata->listenfd = -1;
79 if (fd >= 0) {
80 if (ldata->connect_cb) {
81 ldata->connect_cb(sipe_backend_fd_from_int(fd), ldata->data);
82 } else {
83 close(fd);
87 g_free(ldata);
90 static void
91 backend_listen_cb(int listenfd, struct sipe_backend_listendata *ldata)
93 ldata->listenfd = -1;
94 ldata->listener = NULL;
95 ldata->listenfd = listenfd;
97 if (ldata->listen_cb) {
99 * NOTE: getsockname() on Windows seems to be picky about the
100 * buffer location. Use an allocated buffer instead of
101 * one on the stack,
103 union socket_info {
104 struct sockaddr sa; /* to avoid casts */
105 struct sockaddr_in sa_in; /* IPv4 variant */
106 struct sockaddr_in6 sa_in6; /* IPv6 variant */
107 struct sockaddr_storage unused; /* for alignment */
108 } *si = g_new(union socket_info, 1);
109 socklen_t si_len = sizeof(*si);
110 guint port = htons(0); /* error fallback */
112 if (getsockname(listenfd, &si->sa, &si_len) == 0) {
113 port = (si->sa.sa_family == AF_INET) ? si->sa_in.sin_port :
114 (si->sa.sa_family == AF_INET6) ? si->sa_in6.sin6_port :
115 port;
117 g_free(si);
119 ldata->listen_cb(ntohs(port), ldata->data);
122 ldata->watcher = purple_input_add(listenfd, PURPLE_INPUT_READ,
123 (PurpleInputFunction)client_connected_cb,
124 ldata);
127 struct sipe_backend_listendata *
128 sipe_backend_network_listen_range(unsigned short port_min,
129 unsigned short port_max,
130 sipe_listen_start_cb listen_cb,
131 sipe_client_connected_cb connect_cb,
132 gpointer data)
134 struct sipe_backend_listendata *ldata;
135 ldata = g_new0(struct sipe_backend_listendata, 1);
137 ldata->listen_cb = listen_cb;
138 ldata->connect_cb = connect_cb;
139 ldata->data = data;
140 ldata->listener = purple_network_listen_range(port_min, port_max,
141 #if PURPLE_VERSION_CHECK(3,0,0)
142 /* @TODO: does FT work with IPv6? */
143 AF_INET,
144 #endif
145 SOCK_STREAM,
146 #if PURPLE_VERSION_CHECK(3,0,0)
147 /* @TODO: should we allow external mapping? */
148 FALSE,
149 #endif
150 (PurpleNetworkListenCallback)backend_listen_cb,
151 ldata);
153 if (!ldata->listener) {
154 g_free(ldata);
155 return NULL;
158 return ldata;
161 void sipe_backend_network_listen_cancel(struct sipe_backend_listendata *ldata)
163 g_return_if_fail(ldata);
165 if (ldata->listener)
166 purple_network_listen_cancel(ldata->listener);
167 if (ldata->listenfd)
168 close(ldata->listenfd);
169 g_free(ldata);
172 struct sipe_backend_fd *
173 sipe_backend_fd_from_int(int fd)
175 struct sipe_backend_fd *sipe_fd = g_new(struct sipe_backend_fd, 1);
176 sipe_fd->fd = fd;
177 return sipe_fd;
180 gboolean
181 sipe_backend_fd_is_valid(struct sipe_backend_fd *fd)
183 return fd && fd->fd >= 0;
186 void
187 sipe_backend_fd_free(struct sipe_backend_fd *fd)
189 g_free(fd);
193 Local Variables:
194 mode: c
195 c-file-style: "bsd"
196 indent-tabs-mode: t
197 tab-width: 8
198 End: