1/*
2 * $Id: rend-unix.c,v 1.1 2009-06-30 02:31:09 steven Exp $
3 * General unix rendezvous routines
4 *
5 * Copyright (C) 2003 Ron Pedde (ron@pedde.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (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
22#ifdef HAVE_CONFIG_H
23# include "config.h"
24#endif
25
26#include <errno.h>
27#include <restart.h>
28#include <signal.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#include "daapd.h"
35#include "err.h"
36#include "rend-unix.h"
37
38int rend_pipe_to[2];
39int rend_pipe_from[2];
40int rend_pid;
41
42#define RD_SIDE 0
43#define WR_SIDE 1
44
45/*
46 * rend_init
47 *
48 * Fork and set up message passing system
49 */
50int rend_init(char *user) {
51    int err;
52    int fd;
53
54    if(pipe((int*)&rend_pipe_to) == -1)
55	return -1;
56
57    if(pipe((int*)&rend_pipe_from) == -1) {
58	err=errno;
59	close(rend_pipe_to[RD_SIDE]);
60	close(rend_pipe_to[WR_SIDE]);
61	errno=err;
62	return -1;
63    }
64
65    rend_pid=fork();
66    if(rend_pid==-1) {
67	err=errno;
68	close(rend_pipe_to[RD_SIDE]);
69	close(rend_pipe_to[WR_SIDE]);
70	close(rend_pipe_from[RD_SIDE]);
71	close(rend_pipe_from[WR_SIDE]);
72	errno=err;
73	return -1;
74    }
75
76    if(rend_pid) { /* parent */
77	close(rend_pipe_to[RD_SIDE]);
78	close(rend_pipe_from[WR_SIDE]);
79	return 0;
80    }
81
82    /* child */
83    close(rend_pipe_to[WR_SIDE]);
84    close(rend_pipe_from[RD_SIDE]);
85
86    /* Depending on the backend, this might not get done on the
87     * rendezvous server-specific side
88     */
89    signal(SIGTTOU, SIG_IGN);
90    signal(SIGTTIN, SIG_IGN);
91    signal(SIGTSTP, SIG_IGN);
92
93#ifdef SETPGRP_VOID
94   setpgrp();
95#else
96   setpgrp(0,0);
97#endif
98
99#ifdef TIOCNOTTY
100    if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
101	ioctl(fd, TIOCNOTTY, (char *) NULL);
102	close(fd);
103    }
104#endif
105
106    if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
107	dup2(fd, STDIN_FILENO);
108	dup2(fd, STDOUT_FILENO);
109	dup2(fd, STDERR_FILENO);
110	if (fd > 2)
111	    close(fd);
112    }
113
114    errno = 0;
115
116    chdir("/");
117    umask(0);
118
119    /* something bad here... should really signal the parent, rather
120     * than just zombieizing
121     */
122    rend_private_init(user); /* should only return when terminated */
123    exit(0);
124}
125
126/*
127 * rend_running
128 *
129 * See if the rendezvous daemon is runnig
130 */
131int rend_running(void) {
132    REND_MESSAGE msg;
133    int result;
134
135    DPRINTF(E_DBG,L_REND,"Status inquiry\n");
136    memset((void*)&msg,0x00,sizeof(msg));
137    msg.cmd=REND_MSG_TYPE_STATUS;
138    result=rend_send_message(&msg);
139    DPRINTF(E_DBG,L_REND,"Returning status %d\n",result);
140    return result;
141}
142
143/*
144 *rend_stop
145 *
146 * Stop the rendezvous server
147 */
148int rend_stop(void) {
149    REND_MESSAGE msg;
150
151    msg.cmd=REND_MSG_TYPE_STOP;
152    return rend_send_message(&msg);
153}
154
155/*
156 * rend_register
157 *
158 * register a rendezvous name
159 */
160int rend_register(char *name, char *type, int port) {
161    REND_MESSAGE msg;
162
163    if((strlen(name)+1 > MAX_NAME_LEN) || (strlen(type)+1 > MAX_NAME_LEN)) {
164	DPRINTF(E_FATAL,L_REND,"Registration failed: name or type too long\n");
165	return -1;
166    }
167
168    memset((void*)&msg,0x00,sizeof(msg)); /* shut valgrind up */
169    msg.cmd=REND_MSG_TYPE_REGISTER;
170    strcpy(msg.name,name);
171    strcpy(msg.type,type);
172    msg.port=port;
173
174    return rend_send_message(&msg);
175}
176
177/*
178 * rend_unregister
179 *
180 * Stop advertising a rendezvous name
181 */
182int rend_unregister(char *name, char *type, int port) {
183    return -1; /* not implemented */
184}
185
186/*
187 * rend_send_message
188 *
189 * Send a rendezvous message
190 */
191int rend_send_message(REND_MESSAGE *pmsg) {
192    int retval;
193
194    if(r_write(rend_pipe_to[WR_SIDE],pmsg,sizeof(REND_MESSAGE)) == -1)
195	return -1;
196
197    if((retval=r_read(rend_pipe_from[RD_SIDE],&retval,sizeof(int)) == -1))
198	return -1;
199
200    return retval;
201}
202
203/*
204 * rend_read_message
205 *
206 * read the message passed to the rend daemon
207 */
208int rend_read_message(REND_MESSAGE *pmsg) {
209    return r_read(rend_pipe_to[RD_SIDE],pmsg,sizeof(REND_MESSAGE));
210}
211
212/*
213 * rend_send_response
214 *
215 * Let the rendezvous daemon return a result
216 */
217int rend_send_response(int value) {
218    return r_write(rend_pipe_from[WR_SIDE],&value,sizeof(int));
219}
220