Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <errno.h>
11 : #include <stdlib.h>
12 : #include <string.h>
13 : #include <algorithm>
14 : #include <vector>
15 : #include <iostream>
16 :
17 : #include <comphelper/processfactory.hxx>
18 : #include <rtl/strbuf.hxx>
19 : #include <config_features.h>
20 :
21 : #include "DiscoveryService.hxx"
22 :
23 : #ifdef WIN32
24 : // LO vs WinAPI conflict
25 : #undef WB_LEFT
26 : #undef WB_RIGHT
27 :
28 : #include <winsock2.h>
29 : #include <ws2tcpip.h>
30 :
31 : #include "WINNetworkService.hxx"
32 : typedef int socklen_t;
33 : #else
34 : #include <unistd.h>
35 : #include <sys/types.h>
36 : #include <sys/socket.h>
37 : #include <netinet/in.h>
38 : #include <arpa/inet.h>
39 : #endif
40 :
41 : #ifdef MACOSX
42 : #include <osl/conditn.hxx>
43 : #include <premac.h>
44 : #import <CoreFoundation/CoreFoundation.h>
45 : #include <postmac.h>
46 : #import "OSXNetworkService.hxx"
47 : #endif
48 :
49 : #if HAVE_FEATURE_AVAHI
50 : #include "AvahiNetworkService.hxx"
51 : #endif
52 :
53 : using namespace osl;
54 : using namespace sd;
55 :
56 0 : DiscoveryService::DiscoveryService()
57 : : mSocket(-1)
58 0 : , zService(0)
59 : {
60 0 : }
61 :
62 0 : DiscoveryService::~DiscoveryService()
63 : {
64 0 : if (mSocket != -1)
65 : {
66 : #ifdef WNT
67 : closesocket( mSocket );
68 : #else
69 0 : close( mSocket );
70 : #endif
71 : }
72 :
73 0 : if (zService)
74 0 : zService->clear();
75 0 : }
76 :
77 0 : void DiscoveryService::setupSockets()
78 : {
79 :
80 : #ifdef MACOSX
81 : // Bonjour for OSX
82 : zService = new OSXNetworkService();
83 : #endif
84 :
85 : #if HAVE_FEATURE_AVAHI
86 : // Avahi for Linux
87 : char hostname[1024];
88 : hostname[1023] = '\0';
89 : gethostname(hostname, 1023);
90 :
91 : zService = new AvahiNetworkService(hostname);
92 : #endif
93 :
94 : #ifdef WIN32
95 : zService = new WINNetworkService();
96 : #endif
97 :
98 0 : if (zService)
99 0 : zService->setup();
100 :
101 : // Old implementation for backward compatibility matter
102 0 : mSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
103 0 : if (mSocket == -1)
104 : {
105 : SAL_WARN("sd", "DiscoveryService: socket failed: " << errno);
106 0 : return; // would be better to throw, but unsure if caller handles that
107 : }
108 :
109 : sockaddr_in aAddr;
110 0 : memset(&aAddr, 0, sizeof(aAddr));
111 0 : aAddr.sin_family = AF_INET;
112 0 : aAddr.sin_addr.s_addr = htonl(INADDR_ANY);
113 0 : aAddr.sin_port = htons( PORT_DISCOVERY );
114 :
115 0 : int rc = bind( mSocket, reinterpret_cast<sockaddr*>(&aAddr), sizeof(sockaddr_in) );
116 :
117 0 : if (rc)
118 : {
119 : SAL_WARN("sd", "DiscoveryService: bind failed: " << errno);
120 0 : return; // would be better to throw, but unsure if caller handles that
121 : }
122 :
123 : struct ip_mreq multicastRequest;
124 :
125 : // the Win32 SDK 8.1 deprecates inet_addr()
126 : #if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
127 : IN_ADDR addr;
128 : OUString const saddr("239.0.0.1");
129 : INT ret = InetPtonW(AF_INET, saddr.getStr(), & addr);
130 : if (1 == ret)
131 : {
132 : multicastRequest.imr_multiaddr.s_addr = addr.S_un.S_addr;
133 : }
134 : #else
135 0 : multicastRequest.imr_multiaddr.s_addr = inet_addr( "239.0.0.1" );
136 : #endif
137 0 : multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
138 :
139 : rc = setsockopt( mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
140 : #ifdef WNT
141 : (const char*)
142 : #endif
143 0 : &multicastRequest, sizeof(multicastRequest));
144 :
145 0 : if (rc)
146 : {
147 : SAL_WARN("sd", "DiscoveryService: setsockopt failed: " << errno);
148 0 : return; // would be better to throw, but unsure if caller handles that
149 : }
150 : }
151 :
152 0 : void SAL_CALL DiscoveryService::run()
153 : {
154 0 : osl::Thread::setName("DiscoveryService");
155 :
156 0 : setupSockets();
157 :
158 : // Kept for backwrad compatibility
159 : char aBuffer[BUFFER_SIZE];
160 : while ( true )
161 : {
162 0 : memset( aBuffer, 0, sizeof(char) * BUFFER_SIZE );
163 : sockaddr_in aAddr;
164 0 : socklen_t aLen = sizeof( aAddr );
165 0 : if(recvfrom( mSocket, aBuffer, BUFFER_SIZE, 0, reinterpret_cast<sockaddr*>(&aAddr), &aLen ) > 0)
166 : {
167 0 : OString aString( aBuffer, strlen( "LOREMOTE_SEARCH" ) );
168 0 : if ( aString == "LOREMOTE_SEARCH" )
169 : {
170 0 : OStringBuffer aStringBuffer("LOREMOTE_ADVERTISE\n");
171 : aStringBuffer.append( OUStringToOString(
172 0 : osl::SocketAddr::getLocalHostname(), RTL_TEXTENCODING_UTF8 ) )
173 0 : .append( "\n\n" );
174 0 : if ( sendto( mSocket, aStringBuffer.getStr(),
175 0 : aStringBuffer.getLength(), 0, reinterpret_cast<sockaddr*>(&aAddr),
176 0 : sizeof(aAddr) ) <= 0 )
177 : {
178 : // Write error or closed socket -- we are done.
179 0 : return;
180 0 : }
181 0 : }
182 : }
183 : else
184 : {
185 : // Read error or closed socket -- we are done.
186 0 : return;
187 : }
188 0 : }
189 : }
190 :
191 : DiscoveryService *sd::DiscoveryService::spService = NULL;
192 :
193 0 : void DiscoveryService::setup()
194 : {
195 0 : if (spService)
196 0 : return;
197 :
198 0 : spService = new DiscoveryService();
199 0 : spService->create();
200 66 : }
201 :
202 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|