2 * @file purple-network.c
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
24 #include "config.h" /* coverity[hfa: FALSE] */
31 #include "conversation.h"
33 #include "eventloop.h"
36 /* wrappers for write() & friends for socket handling */
37 #include "win32/win32dep.h"
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
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
;
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
);
80 if (ldata
->connect_cb
) {
81 ldata
->connect_cb(sipe_backend_fd_from_int(fd
), ldata
->data
);
91 backend_listen_cb(int listenfd
, struct sipe_backend_listendata
*ldata
)
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
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
:
119 ldata
->listen_cb(ntohs(port
), ldata
->data
);
122 ldata
->watcher
= purple_input_add(listenfd
, PURPLE_INPUT_READ
,
123 (PurpleInputFunction
)client_connected_cb
,
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
,
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
;
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? */
146 #if PURPLE_VERSION_CHECK(3,0,0)
147 /* @TODO: should we allow external mapping? */
150 (PurpleNetworkListenCallback
)backend_listen_cb
,
153 if (!ldata
->listener
) {
161 void sipe_backend_network_listen_cancel(struct sipe_backend_listendata
*ldata
)
163 g_return_if_fail(ldata
);
166 purple_network_listen_cancel(ldata
->listener
);
168 close(ldata
->listenfd
);
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);
181 sipe_backend_fd_is_valid(struct sipe_backend_fd
*fd
)
183 return fd
&& fd
->fd
>= 0;
187 sipe_backend_fd_free(struct sipe_backend_fd
*fd
)