1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2006 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26
27 #include <stdio.h>
28 #include <string.h>
29
30 #if defined (WIN32)
31 #include <winsock2.h>
32 #include <ws2tcpip.h>
33 #include <process.h>
34 #include <windows.h>
35 #else
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <signal.h>
39 #include <arpa/inet.h> /* htonl() */
40 #include <unistd.h> /* fork */
41 #endif
42
43 #include <libwzd-core/wzd_structs.h>
44 #include <libwzd-core/wzd_log.h>
45
46 #include <libwzd-core/wzd_configfile.h>
47 #include <libwzd-core/wzd_mod.h>
48 #include <libwzd-core/wzd_string.h>
49
50 #ifndef WIN32
51 #include <pthread.h>
52 #endif
53 #include <libwzd-core/wzd_threads.h>
54
55 /* use this define if you want to use
56 processes instead of threads. */
57 /* #define ZEROCONF_USE_PROCESS */
58
59 /* function prototypes and globals */
60 #include "libwzd_zeroconf.h"
61
62 /***********************/
63 MODULE_NAME(zeroconf);
64 MODULE_VERSION(101);
65
66 static void * routine (void * arg);
67
68 #ifdef ZEROCONF_USE_PROCESS
69 static pid_t pid_child = 0;
70 #else
71 static wzd_thread_t zeroconf_thread;
72 #endif
73
74 static int initialized = 0;
75
76 #ifdef USE_AVAHI
77 struct context *ctx = NULL;
78 #endif
79
80 #ifdef ZEROCONF_USE_PROCESS
sighandler(int sig)81 static void sighandler(int sig)
82 {
83 out_log(LEVEL_FLOOD,"zeroconf: received signal %d\n",sig);
84 #ifdef USE_AVAHI
85 if (ctx)
86 av_zeroconf_shutdown(ctx);
87 #elif defined (USE_HOWL)
88 ho_zeroconf_unregister();
89 #elif defined (USE_BONJOUR)
90 bo_zeroconf_unregister();
91 #endif
92 }
93 #endif
94
WZD_MODULE_INIT(void)95 int WZD_MODULE_INIT(void)
96 {
97 wzd_string_t * str;
98 int err;
99 int ret = 1;
100 void * arg = NULL;
101 const char *zeroconf_name = NULL;
102 const char *zeroconf_username = NULL;
103 const char *zeroconf_password = NULL;
104 const char *zeroconf_path = NULL;
105 unsigned long wzdftpd_port;
106
107 if (initialized > 0) return 1;
108 initialized++;
109
110 /* the mDNS name that should be published */
111 str = config_get_string(mainConfig->cfg_file, "ZEROCONF", "zeroconf_name", NULL);
112 if (str) {
113 zeroconf_name = strdup(str_tochar(str));
114 str_deallocate(str);
115 }
116
117 /* TXT keys - see http://www.dns-sd.org/ServiceTypes.html */
118 str = config_get_string(mainConfig->cfg_file, "ZEROCONF", "zeroconf_username", NULL);
119 if (str) {
120 zeroconf_username = strdup(str_tochar(str));
121 str_deallocate(str);
122 }
123
124 str = config_get_string(mainConfig->cfg_file, "ZEROCONF", "zeroconf_password", NULL);
125 if (str) {
126 zeroconf_password = strdup(str_tochar(str));
127 str_deallocate(str);
128 }
129
130 str = config_get_string(mainConfig->cfg_file, "ZEROCONF", "zeroconf_path", NULL);
131 if (str) {
132 zeroconf_path = strdup(str_tochar(str));
133 str_deallocate(str);
134 }
135
136 /** the actual port
137 * \todo determine port(s) dynamically from port = ...
138 * \todo support multiple ports
139 */
140 wzdftpd_port = config_get_integer(mainConfig->cfg_file, "ZEROCONF", "zeroconf_port", &err);
141 if (err) {
142 out_log(LEVEL_CRITICAL,"zeroconf: you must provide zeroconf_port=... in your config file\n");
143 initialized = 0;
144 return -1;
145 }
146
147 #ifdef ZEROCONF_USE_PROCESS
148 pid_child = fork();
149 if (pid_child < 0) {
150 out_log(LEVEL_CRITICAL,"zeroconf: could not create a new process\n");
151 initialized = 0;
152 return -1;
153 }
154 if (pid_child > 0) {
155 return 0;
156 }
157 {
158 sigset_t mask;
159 sigfillset(&mask);
160 ret = pthread_sigmask(SIG_UNBLOCK,&mask,NULL);
161 if (pid_child < 0) {
162 out_log(LEVEL_CRITICAL,"zeroconf: could not unblock pthread signals mask\n");
163 initialized = 0;
164 return -1;
165 }
166 }
167 # ifdef DEBUG
168 /* We MUST close stdin, or the keyboard interrupts (like Ctrl+C) will be sent to both
169 * the server and the zeroconf module
170 */
171 close(0);
172 # endif
173 /* We have to override ALL the signals trapped in wzd_ServerThread.c
174 * Since this process is created by fork(), it inheritates the file descriptors AND signal
175 * handlers, so the server's handler would be called in the forked process !
176 */
177 signal(SIGINT,sighandler);
178 signal(SIGTERM,sighandler);
179 signal(SIGHUP,SIG_DFL);
180 #endif
181
182 #ifdef USE_BONJOUR
183 /*
184 TODO: This has to be tested on a OSX box. Especially whether it
185 blocks the main wzdftpd loop/thread.
186 */
187 bo_zeroconf_setup(wzdftpd_port,
188 zeroconf_name,
189 zeroconf_username,
190 zeroconf_password,
191 zeroconf_path);
192 #elif defined (USE_AVAHI)
193 if (wzdftpd_port == 0) return 1; // the port should be defined in the config file
194
195 ctx = av_zeroconf_setup(wzdftpd_port,
196 zeroconf_name,
197 zeroconf_username,
198 zeroconf_password,
199 zeroconf_path);
200 #elif defined (USE_HOWL)
201 ho_zeroconf_setup(wzdftpd_port,
202 zeroconf_name,
203 zeroconf_username,
204 zeroconf_password,
205 zeroconf_path);
206 #endif
207
208 out_log(LEVEL_INFO, "Module zeroconf loaded\n");
209
210 #ifdef ZEROCONF_USE_PROCESS
211 routine(arg);
212 exit (0);
213 #else
214 ret = wzd_thread_create (&zeroconf_thread, NULL, &routine, arg);
215 #endif
216
217 return 0;
218 }
219
WZD_MODULE_CLOSE(void)220 void WZD_MODULE_CLOSE(void)
221 {
222 int ret;
223 #ifndef ZEROCONF_USE_PROCESS
224 void * thread_return;
225 #endif
226
227 if (initialized) {
228 #ifdef ZEROCONF_USE_PROCESS
229 kill(pid_child,SIGTERM);
230 #else
231 # ifdef USE_AVAHI
232 if (ctx)
233 av_zeroconf_shutdown(ctx);
234 # elif defined (USE_BONJOUR)
235 bo_zeroconf_unregister();
236 # elif defined (USE_HOWL)
237 ho_zeroconf_unregister();
238 # endif
239 #endif
240
241 #ifdef ZEROCONF_USE_PROCESS
242 ret = wait4(pid_child, NULL, 0, NULL);
243 #else
244 ret = wzd_thread_join(&zeroconf_thread, &thread_return);
245 #endif
246 }
247
248 out_log(LEVEL_INFO, "Module zeroconf unloaded\n");
249 }
250
routine(void * arg)251 static void * routine (void * arg)
252 {
253 #ifdef USE_AVAHI
254 /* Now start the loop.
255 * Note: run does not block the main loop. Tho It will create a new thread.
256 */
257 av_zeroconf_run(ctx);
258 # ifndef ZEROCONF_USE_PROCESS
259 # endif
260 #elif defined (USE_HOWL)
261 ho_zeroconf_run();
262 #elif defined (USE_BONJOUR)
263 bo_zeroconf_run();
264 #endif
265
266 return NULL;
267 }
268