1 /* $Header: /home/cvs/wavplay/client.c,v 1.2 1999/12/04 00:01:20 wwg Exp $
2  * Warren W. Gay VE3WWG		Tue Feb 25 22:43:40 1997
3  *
4  * CLIENT RELATED FUNCTIONS:
5  *
6  * 	X LessTif WAV Play :
7  *
8  * 	Copyright (C) 1997  Warren W. Gay VE3WWG
9  *
10  * This  program is free software; you can redistribute it and/or modify it
11  * under the  terms  of  the GNU General Public License as published by the
12  * Free Software Foundation version 2 of the License.
13  *
14  * This  program  is  distributed  in  the hope that it will be useful, but
15  * WITHOUT   ANY   WARRANTY;   without   even  the   implied   warranty  of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17  * Public License for more details (see enclosed file COPYING).
18  *
19  * You  should have received a copy of the GNU General Public License along
20  * with this  program; if not, write to the Free Software Foundation, Inc.,
21  * 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * Send correspondance to:
24  *
25  * 	Warren W. Gay VE3WWG
26  *
27  * Email:
28  *	ve3wwg@yahoo.com
29  *	wgay@mackenziefinancial.com
30  *
31  * $Log: client.c,v $
32  * Revision 1.2  1999/12/04 00:01:20  wwg
33  * Implement wavplay-1.4 release changes
34  *
35  * Revision 1.1.1.1  1999/11/21 19:50:56  wwg
36  * Import wavplay-1.3 into CVS
37  *
38  * Revision 1.1  1997/04/14 00:11:03  wwg
39  * Initial revision
40  */
41 static const char rcsid[] = "@(#)client.c $Revision: 1.2 $";
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <time.h>
50 #ifndef FREEBSD
51 #include <malloc.h>
52 #endif
53 #include <string.h>
54 #include <memory.h>
55 #include <signal.h>
56 #include <sys/types.h>
57 #include <sys/ipc.h>
58 #include <sys/msg.h>
59 #include <sys/wait.h>
60 #include <sys/stat.h>
61 #include <assert.h>
62 #ifndef FREEBSD
63 #include <linux/soundcard.h>
64 #else
65 #include <sys/soundcard.h>
66 #endif
67 #include "wavplay.h"
68 #include "client.h"
69 
70 pid_t svrPID = (pid_t)-1;					/* Forked process ID of server */
71 int svrIPC = -1;						/* IPC ID of message queue */
72 static ErrFunc v_erf;						/* Error reporting function */
73 
74 /*
75  * Error reporting function for this source module:
76  */
77 static void
err(const char * format,...)78 err(const char *format,...) {
79 	va_list ap;
80 
81 	if ( v_erf == NULL )
82 		return;				/* Only report error if we have function */
83 	va_start(ap,format);
84 	v_erf(format,ap);			/* Use caller's supplied function */
85 	va_end(ap);
86 }
87 
88 /*
89  * This function is called at exit()
90  */
91 static void
close_msgq(void)92 close_msgq(void) {
93 	int termstat;						/* Process termination status */
94 	pid_t PID;						/* PID from waitpid() */
95 	time_t t0, t1;						/* Times for timeout */
96 
97 	if ( svrIPC >= 0 )
98 		tosvr_bye(0,NULL);				/* Tell server to exit politely */
99 	else if ( svrPID != (pid_t) -1L )
100 		kill(svrPID,SIGTERM);				/* It has no msg queue anyhow */
101 
102 	/*
103 	 * Leave some time for the server to exit:
104 	 */
105 	if ( svrPID != (pid_t) -1L ) {				/* Did we start a fork? */
106 		time(&t0);					/* Start timer */
107 
108 		do	{					/* Loop while server runs */
109 			if ( (PID = waitpid(-1,&termstat,WNOHANG)) == svrPID ) {
110 				svrPID = (pid_t) -1L;		/* Note the termination */
111 				break;				/* Server ended */
112 			}
113 			time(&t1);
114 			sleep(1);				/* Give up CPU */
115 		} while ( PID < 1 && t1 - t0 < 4 );		/* Eventually timeout */
116 	}
117 
118 	if ( svrIPC >= 0 )
119 		MsgClose(svrIPC);				/* Remove message queue */
120 
121 	if ( svrPID != (pid_t) -1L )
122 		kill(svrPID,SIGTERM);				/* Stab it again */
123 }
124 
125 /*
126  * Fork the server, and get it started:
127  */
128 int
tosvr_start(ErrFunc erf)129 tosvr_start(ErrFunc erf) {
130 	int e;					/* Saved errno value */
131 	char buf[200];				/* Argv[0] for exec'd process */
132 	SVRMSG msg;				/* Server message from wavplay */
133 	pid_t PID;				/* Process ID of terminated process */
134 	int termstat;				/* Termination status of the process */
135 	time_t t0, t;				/* Start time, current time */
136 
137 	v_erf = erf;				/* Error reporting function */
138 
139 	/*
140 	 * Create a private message queue for the client<-->server
141 	 * communications.
142 	 */
143 	if ( (svrIPC = MsgCreate()) < 0 ) {
144 		err("%s: creating message queue",sys_errlist[errno]);
145 		return -1;
146 	}
147 
148 	sprintf(buf,"WAVSVR=%d",svrIPC);	/* Pass this as argv[0] */
149 
150 	/*
151 	 * Create a fork, that will then exec wavplay as a server:
152 	 */
153 	if ( (svrPID = fork()) == (pid_t)0L ) {
154 		/*
155 		 * Child process must now start the wavplay command as server:
156 		 */
157 		if ( cmdopt_x )
158 			execl(env_WAVPLAYPATH,buf,"-x",NULL);	/* Debug On */
159 		else	execl(env_WAVPLAYPATH,buf,NULL);	/* No debug yet */
160 
161 		/* Returns only if error occurs */
162 		fprintf(stderr,"%s: exec of %s\n",sys_errlist[errno],env_WAVPLAYPATH);
163 		exit(2);
164 
165 	} else if ( svrPID < 0 ) {
166 		e = errno;
167 		err("%s: forking the server process",sys_errlist[errno]);
168 		MsgClose(svrIPC);
169 		errno = e;			/* Restore error code */
170 		return -1;
171 	}
172 
173 	atexit(close_msgq);			/* Invoke close_msgq() at exit() time */
174 
175 	time(&t0);				/* Start clock */
176 
177 	while ( 1 ) {
178 		if ( !MsgFromServer(svrIPC,&msg,IPC_NOWAIT) ) {
179 			/*
180 			 * We have a message from the server:
181 			 */
182 			if ( msg.msg_type == ToClnt_Ready )
183 				return 0;	/* We connected to server OK! */
184 			fprintf(stderr,"Bad server message: %d\n",(int)msg.msg_type);
185 
186 		} else	{
187 			while ( (PID = waitpid(-1,&termstat,WNOHANG)) == -1 && errno == EINTR )
188 				;	/* Repeat interrupted system call */
189 			if ( PID > 0 ) {
190 				/*
191 				 * We have terminated process!
192 				 */
193 				err("Server process ID %ld terminated: %s",PID,ProcTerm(termstat));
194 				return -1;
195 
196 			} else	sleep(1);
197 		}
198 
199 		time(&t);
200 		if ( t - t0 > 5 )
201 			break;
202 	}
203 
204 	err("Timeout: starting server.");
205 	kill(svrPID,SIGTERM);
206 	return -1;
207 }
208 
209 /*
210  * Send simple command to server:
211  */
212 int
tosvr_cmd(MSGTYP cmd,int flags,ErrFunc erf)213 tosvr_cmd(MSGTYP cmd,int flags,ErrFunc erf) {
214 	SVRMSG msg;
215 	int rc;
216 
217 	v_erf = erf;				/* Error reporting function */
218 
219 	msg.msg_type = cmd;
220 	msg.bytes = 0;				/* Simple commands have no other data */
221 
222 	if ( (rc = MsgSend(svrIPC,&msg,flags,MSGNO_SRVR)) != 0 && erf != NULL )
223 		err("%s: Sending server message '%s'",
224 			msg_name(cmd),
225 			sys_errlist[errno]);
226 	return rc;				/* Zero indicates success */
227 }
228 
229 /*
230  * Send a pathname to the server:
231  */
232 int
tosvr_path(const char * pathname,int flags,ErrFunc erf)233 tosvr_path(const char *pathname,int flags,ErrFunc erf) {
234 	SVRMSG msg;
235 	int z;
236 
237 	v_erf = erf;				/* Error reporting function */
238 
239 	msg.msg_type = ToSvr_Path;
240 	strncpy(msg.u.tosvr_path.path,pathname,sizeof msg.u.tosvr_path)
241 		[sizeof msg.u.tosvr_path.path - 1] = 0;
242 	msg.bytes = strlen(msg.u.tosvr_path.path);
243 
244 	if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
245 		err("%s: Sending server message 'path'",sys_errlist[errno]);
246 	return z;
247 }
248 
249 /*
250  * Tell server about new data bits per sample setting:
251  */
252 int
tosvr_bits(int flags,ErrFunc erf,int bits)253 tosvr_bits(int flags,ErrFunc erf,int bits) {
254 	SVRMSG msg;
255 	int z;
256 
257 	v_erf = erf;				/* Error reporting function */
258 
259 	msg.msg_type = ToSvr_Bits;
260 	msg.u.tosvr_bits.DataBits = bits;
261 	msg.bytes = sizeof msg.u.tosvr_bits;
262 
263 	if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
264 		err("%s: Sending server message 'bits'",sys_errlist[errno]);
265 
266 	return z;
267 }
268 
269 /*
270  * Tell server to start at a new sample number:
271  */
272 int
tosvr_start_sample(int flags,ErrFunc erf,UInt32 sample)273 tosvr_start_sample(int flags, ErrFunc erf, UInt32 sample) {
274        SVRMSG msg;
275        int z;
276 
277        v_erf = erf;                            /* Error reporting function */
278 
279        msg.msg_type = ToSvr_StartSample;
280        msg.u.tosvr_start_sample.StartSample = sample;
281        msg.bytes = sizeof msg.u.tosvr_start_sample;
282 
283        if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
284                err("%s: Sending server message 'start_sample'",sys_errlist[errno]);
285 
286        return z;
287 }
288 /*
289  * Tell server to use new sampling rate:
290  */
291 int
tosvr_sampling_rate(int flags,ErrFunc erf,UInt32 sampling_rate)292 tosvr_sampling_rate(int flags,ErrFunc erf,UInt32 sampling_rate) {
293 	SVRMSG msg;
294 	int z;
295 
296 	v_erf = erf;				/* Error reporting function */
297 
298 	msg.msg_type = ToSvr_SamplingRate;
299 	msg.u.tosvr_sampling_rate.SamplingRate = sampling_rate;
300 	msg.bytes = sizeof msg.u.tosvr_sampling_rate;
301 
302 	if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
303 		err("%s: Sending server message 'sampling_rate'",sys_errlist[errno]);
304 
305 	return z;
306 }
307 
308 /*
309  * Tell server about Mono/Stereo preference:
310  */
311 int
tosvr_chan(int flags,ErrFunc erf,Chan chan)312 tosvr_chan(int flags,ErrFunc erf,Chan chan) {
313 	SVRMSG msg;
314 	int z;
315 
316 	v_erf = erf;				/* Error reporting function */
317 
318 	msg.msg_type = ToSvr_Chan;
319 	msg.u.tosvr_chan.Channels = chan;
320 	msg.bytes = sizeof msg.u.tosvr_chan;
321 
322 	if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
323 		err("%s: Sending server message 'tosvr_chan'",sys_errlist[errno]);
324 
325 	return z;
326 }
327 
328 /*
329  * Tell server to start recording:
330  */
331 int
tosvr_record(int flags,ErrFunc erf,Chan Channels,UInt32 SamplingRate,UInt16 DataBits)332 tosvr_record(int flags,ErrFunc erf,Chan Channels,UInt32 SamplingRate,UInt16 DataBits) {
333 	SVRMSG msg;
334 	int z;
335 
336 	v_erf = erf;				/* Error reporting function */
337 
338 	msg.msg_type = ToSvr_Record;
339 	msg.u.tosvr_record.Channels = Channels;
340 	msg.u.tosvr_record.SamplingRate = SamplingRate;
341 	msg.u.tosvr_record.DataBits = DataBits;
342 	msg.bytes = sizeof msg.u.tosvr_record;
343 
344 	if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
345 		err("%s: Sending server message 'tosvr_record'",sys_errlist[errno]);
346 
347 	return z;
348 }
349 
350 /*
351  * Tell server about our current debug level setting:
352  */
353 int
tosvr_debug(int flags,ErrFunc erf,int bDebugMode)354 tosvr_debug(int flags,ErrFunc erf,int bDebugMode) {
355 	SVRMSG msg;
356 	int z;
357 
358 	v_erf = erf;				/* Error reporting function */
359 
360 	msg.msg_type = ToSvr_Debug;
361 	msg.u.tosvr_debug.bDebugMode = bDebugMode;
362 	msg.bytes = sizeof msg.u.tosvr_debug;
363 
364 	if ( (z = MsgToServer(svrIPC,&msg,flags)) != 0 && erf != NULL )
365 		err("%s: Sending server message 'tosvr_debug'",sys_errlist[errno]);
366 
367 	return z;
368 }
369 
370 /* $Source: /home/cvs/wavplay/client.c,v $ */
371