diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_inter.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/s_inter.c | 2000 |
1 files changed, 2000 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_inter.c b/apps/plugins/pdbox/PDa/src/s_inter.c new file mode 100644 index 0000000000..37c44770ed --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/s_inter.c | |||
@@ -0,0 +1,2000 @@ | |||
1 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
2 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
3 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
4 | |||
5 | /* Pd side of the Pd/Pd-gui interface. Also, some system interface routines | ||
6 | that didn't really belong anywhere. */ | ||
7 | |||
8 | #include "m_pd.h" | ||
9 | #include "s_stuff.h" | ||
10 | #include "m_imp.h" | ||
11 | #ifdef UNIX | ||
12 | #include <unistd.h> | ||
13 | #include <sys/socket.h> | ||
14 | #include <netinet/in.h> | ||
15 | #include <netinet/tcp.h> | ||
16 | #include <netdb.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <sys/time.h> | ||
19 | #include <sys/mman.h> | ||
20 | #endif | ||
21 | #ifdef HAVE_BSTRING_H | ||
22 | #include <bstring.h> | ||
23 | #endif | ||
24 | #ifdef MSW | ||
25 | #include <io.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <process.h> | ||
28 | #include <winsock.h> | ||
29 | typedef int pid_t; | ||
30 | #define EADDRINUSE WSAEADDRINUSE | ||
31 | #endif | ||
32 | #include <stdarg.h> | ||
33 | #include <signal.h> | ||
34 | #include <fcntl.h> | ||
35 | #include <errno.h> | ||
36 | #include <string.h> | ||
37 | #include <stdio.h> | ||
38 | |||
39 | #ifdef MACOSX | ||
40 | #include <sys/types.h> | ||
41 | #include <sys/stat.h> | ||
42 | #include <pthread.h> | ||
43 | #else | ||
44 | #include <stdlib.h> | ||
45 | #endif | ||
46 | |||
47 | #define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */ | ||
48 | #define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */ | ||
49 | |||
50 | /* T.Grill - make it a _little_ more adaptable... */ | ||
51 | #ifndef PDBINDIR | ||
52 | #define PDBINDIR "bin/" | ||
53 | #endif | ||
54 | |||
55 | #ifndef WISHAPP | ||
56 | #define WISHAPP "wish83.exe" | ||
57 | #endif | ||
58 | |||
59 | extern char pd_version[]; | ||
60 | |||
61 | typedef struct _fdpoll | ||
62 | { | ||
63 | int fdp_fd; | ||
64 | t_fdpollfn fdp_fn; | ||
65 | void *fdp_ptr; | ||
66 | } t_fdpoll; | ||
67 | |||
68 | #define INBUFSIZE 4096 | ||
69 | |||
70 | struct _socketreceiver | ||
71 | { | ||
72 | char *sr_inbuf; | ||
73 | int sr_inhead; | ||
74 | int sr_intail; | ||
75 | void *sr_owner; | ||
76 | int sr_udp; | ||
77 | t_socketnotifier sr_notifier; | ||
78 | t_socketreceivefn sr_socketreceivefn; | ||
79 | }; | ||
80 | |||
81 | static int sys_nfdpoll; | ||
82 | static t_fdpoll *sys_fdpoll; | ||
83 | static int sys_maxfd; | ||
84 | static int sys_guisock; | ||
85 | |||
86 | static t_binbuf *inbinbuf; | ||
87 | static t_socketreceiver *sys_socketreceiver; | ||
88 | extern int sys_addhist(int phase); | ||
89 | |||
90 | #ifdef MSW | ||
91 | static LARGE_INTEGER nt_inittime; | ||
92 | static double nt_freq = 0; | ||
93 | |||
94 | static void sys_initntclock(void) | ||
95 | { | ||
96 | LARGE_INTEGER f1; | ||
97 | LARGE_INTEGER now; | ||
98 | QueryPerformanceCounter(&now); | ||
99 | if (!QueryPerformanceFrequency(&f1)) | ||
100 | { | ||
101 | fprintf(stderr, "pd: QueryPerformanceFrequency failed\n"); | ||
102 | f1.QuadPart = 1; | ||
103 | } | ||
104 | nt_freq = f1.QuadPart; | ||
105 | nt_inittime = now; | ||
106 | } | ||
107 | |||
108 | #if 0 | ||
109 | /* this is a version you can call if you did the QueryPerformanceCounter | ||
110 | call yourself. Necessary for time tagging incoming MIDI at interrupt | ||
111 | level, for instance; but we're not doing that just now. */ | ||
112 | |||
113 | double nt_tixtotime(LARGE_INTEGER *dumbass) | ||
114 | { | ||
115 | if (nt_freq == 0) sys_initntclock(); | ||
116 | return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq); | ||
117 | } | ||
118 | #endif | ||
119 | #endif /* MSW */ | ||
120 | |||
121 | /* get "real time" in seconds; take the | ||
122 | first time we get called as a reference time of zero. */ | ||
123 | t_time sys_getrealtime(void) | ||
124 | { | ||
125 | #ifdef UNIX | ||
126 | static struct timeval then; | ||
127 | struct timeval now; | ||
128 | gettimeofday(&now, 0); | ||
129 | if (then.tv_sec == 0 && then.tv_usec == 0) then = now; | ||
130 | return (now.tv_sec - then.tv_sec)*1000000 + | ||
131 | (now.tv_usec - then.tv_usec); | ||
132 | #endif | ||
133 | #ifdef MSW | ||
134 | LARGE_INTEGER now; | ||
135 | QueryPerformanceCounter(&now); | ||
136 | if (nt_freq == 0) sys_initntclock(); | ||
137 | return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq); | ||
138 | #endif | ||
139 | } | ||
140 | |||
141 | void sys_sockerror(char *s) | ||
142 | { | ||
143 | #ifdef MSW | ||
144 | int err = WSAGetLastError(); | ||
145 | if (err == 10054) return; | ||
146 | else if (err == 10044) | ||
147 | { | ||
148 | fprintf(stderr, | ||
149 | "Warning: you might not have TCP/IP \"networking\" turned on\n"); | ||
150 | fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n"); | ||
151 | } | ||
152 | #endif | ||
153 | #ifdef UNIX | ||
154 | int err = errno; | ||
155 | #endif | ||
156 | fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err); | ||
157 | } | ||
158 | |||
159 | void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr) | ||
160 | { | ||
161 | int nfd = sys_nfdpoll; | ||
162 | int size = nfd * sizeof(t_fdpoll); | ||
163 | t_fdpoll *fp; | ||
164 | sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, | ||
165 | size + sizeof(t_fdpoll)); | ||
166 | fp = sys_fdpoll + nfd; | ||
167 | fp->fdp_fd = fd; | ||
168 | fp->fdp_fn = fn; | ||
169 | fp->fdp_ptr = ptr; | ||
170 | sys_nfdpoll = nfd + 1; | ||
171 | if (fd >= sys_maxfd) sys_maxfd = fd + 1; | ||
172 | } | ||
173 | |||
174 | void sys_rmpollfn(int fd) | ||
175 | { | ||
176 | int nfd = sys_nfdpoll; | ||
177 | int i, size = nfd * sizeof(t_fdpoll); | ||
178 | t_fdpoll *fp; | ||
179 | for (i = nfd, fp = sys_fdpoll; i--; fp++) | ||
180 | { | ||
181 | if (fp->fdp_fd == fd) | ||
182 | { | ||
183 | while (i--) | ||
184 | { | ||
185 | fp[0] = fp[1]; | ||
186 | fp++; | ||
187 | } | ||
188 | sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, | ||
189 | size - sizeof(t_fdpoll)); | ||
190 | sys_nfdpoll = nfd - 1; | ||
191 | return; | ||
192 | } | ||
193 | } | ||
194 | post("warning: %d removed from poll list but not found", fd); | ||
195 | } | ||
196 | |||
197 | static int sys_domicrosleep(int microsec, int pollem) | ||
198 | { | ||
199 | struct timeval timout; | ||
200 | int i, didsomething = 0; | ||
201 | t_fdpoll *fp; | ||
202 | timout.tv_sec = 0; | ||
203 | timout.tv_usec = microsec; | ||
204 | if (pollem) | ||
205 | { | ||
206 | fd_set readset, writeset, exceptset; | ||
207 | FD_ZERO(&writeset); | ||
208 | FD_ZERO(&readset); | ||
209 | FD_ZERO(&exceptset); | ||
210 | for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++) | ||
211 | FD_SET(fp->fdp_fd, &readset); | ||
212 | select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout); | ||
213 | for (i = 0; i < sys_nfdpoll; i++) | ||
214 | if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset)) | ||
215 | { | ||
216 | (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd); | ||
217 | didsomething = 1; | ||
218 | } | ||
219 | return (didsomething); | ||
220 | } | ||
221 | else | ||
222 | { | ||
223 | select(0, 0, 0, 0, &timout); | ||
224 | return (0); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | void sys_microsleep(int microsec) | ||
229 | { | ||
230 | sys_domicrosleep(microsec, 1); | ||
231 | } | ||
232 | |||
233 | t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier, | ||
234 | t_socketreceivefn socketreceivefn, int udp) | ||
235 | { | ||
236 | t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x)); | ||
237 | x->sr_inhead = x->sr_intail = 0; | ||
238 | x->sr_owner = owner; | ||
239 | x->sr_notifier = notifier; | ||
240 | x->sr_socketreceivefn = socketreceivefn; | ||
241 | x->sr_udp = udp; | ||
242 | if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");; | ||
243 | return (x); | ||
244 | } | ||
245 | |||
246 | void socketreceiver_free(t_socketreceiver *x) | ||
247 | { | ||
248 | free(x->sr_inbuf); | ||
249 | freebytes(x, sizeof(*x)); | ||
250 | } | ||
251 | |||
252 | /* this is in a separately called subroutine so that the buffer isn't | ||
253 | sitting on the stack while the messages are getting passed. */ | ||
254 | static int socketreceiver_doread(t_socketreceiver *x) | ||
255 | { | ||
256 | char messbuf[INBUFSIZE], *bp = messbuf; | ||
257 | int indx; | ||
258 | int inhead = x->sr_inhead; | ||
259 | int intail = x->sr_intail; | ||
260 | char *inbuf = x->sr_inbuf; | ||
261 | if (intail == inhead) return (0); | ||
262 | for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) | ||
263 | { | ||
264 | /* if we hit a semi that isn't preceeded by a \, it's a message | ||
265 | boundary. LATER we should deal with the possibility that the | ||
266 | preceeding \ might itself be escaped! */ | ||
267 | char c = *bp++ = inbuf[indx]; | ||
268 | if (c == ';' && (!indx || inbuf[indx-1] != '\\')) | ||
269 | { | ||
270 | intail = (indx+1)&(INBUFSIZE-1); | ||
271 | binbuf_text(inbinbuf, messbuf, bp - messbuf); | ||
272 | if (sys_debuglevel & DEBUG_MESSDOWN) | ||
273 | { | ||
274 | write(2, messbuf, bp - messbuf); | ||
275 | write(2, "\n", 1); | ||
276 | } | ||
277 | x->sr_inhead = inhead; | ||
278 | x->sr_intail = intail; | ||
279 | return (1); | ||
280 | } | ||
281 | } | ||
282 | return (0); | ||
283 | } | ||
284 | |||
285 | static void socketreceiver_getudp(t_socketreceiver *x, int fd) | ||
286 | { | ||
287 | char buf[INBUFSIZE+1]; | ||
288 | int ret = recv(fd, buf, INBUFSIZE, 0); | ||
289 | if (ret < 0) | ||
290 | { | ||
291 | sys_sockerror("recv"); | ||
292 | sys_rmpollfn(fd); | ||
293 | sys_closesocket(fd); | ||
294 | } | ||
295 | else if (ret > 0) | ||
296 | { | ||
297 | buf[ret] = 0; | ||
298 | #if 0 | ||
299 | post("%s", buf); | ||
300 | #endif | ||
301 | if (buf[ret-1] != '\n') | ||
302 | { | ||
303 | #if 0 | ||
304 | buf[ret] = 0; | ||
305 | error("dropped bad buffer %s\n", buf); | ||
306 | #endif | ||
307 | } | ||
308 | else | ||
309 | { | ||
310 | char *semi = strchr(buf, ';'); | ||
311 | if (semi) | ||
312 | *semi = 0; | ||
313 | binbuf_text(inbinbuf, buf, strlen(buf)); | ||
314 | outlet_setstacklim(); | ||
315 | if (x->sr_socketreceivefn) | ||
316 | (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); | ||
317 | else bug("socketreceiver_getudp"); | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | |||
323 | |||
324 | #include <termios.h> | ||
325 | #include <string.h> | ||
326 | |||
327 | static struct termios stored_settings; | ||
328 | EXTERN int sys_stdin; | ||
329 | |||
330 | void set_keypress(void) | ||
331 | { | ||
332 | struct termios new_settings; | ||
333 | |||
334 | tcgetattr(0,&stored_settings); | ||
335 | |||
336 | new_settings = stored_settings; | ||
337 | |||
338 | /* Disable canonical mode, and set buffer size to 1 byte */ | ||
339 | new_settings.c_lflag &= (~ICANON); | ||
340 | new_settings.c_cc[VTIME] = 0; | ||
341 | new_settings.c_cc[VMIN] = 1; | ||
342 | |||
343 | /* echo off */ | ||
344 | new_settings.c_lflag &= (~ECHO); | ||
345 | |||
346 | tcsetattr(0,TCSANOW,&new_settings); | ||
347 | return; | ||
348 | } | ||
349 | |||
350 | void reset_keypress(void) | ||
351 | { | ||
352 | if (sys_stdin) | ||
353 | tcsetattr(0,TCSANOW,&stored_settings); | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | static t_symbol* _ss; | ||
358 | |||
359 | |||
360 | void stdin_read(t_socketreceiver *x, int fd) { | ||
361 | static char input[256]; | ||
362 | |||
363 | char* in; | ||
364 | int got; | ||
365 | |||
366 | got = read(fd,input,256); | ||
367 | in = input; | ||
368 | while (got-- && _ss->s_thing) | ||
369 | pd_float(_ss->s_thing,(float)*in++); | ||
370 | } | ||
371 | |||
372 | void socketreceiver_read(t_socketreceiver *x, int fd) | ||
373 | { | ||
374 | if (x->sr_udp) /* UDP ("datagram") socket protocol */ | ||
375 | socketreceiver_getudp(x, fd); | ||
376 | else /* TCP ("streaming") socket protocol */ | ||
377 | { | ||
378 | char *semi; | ||
379 | int readto = | ||
380 | (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); | ||
381 | int ret; | ||
382 | |||
383 | /* the input buffer might be full. If so, drop the whole thing */ | ||
384 | if (readto == x->sr_inhead) | ||
385 | { | ||
386 | fprintf(stderr, "pd: dropped message from gui\n"); | ||
387 | x->sr_inhead = x->sr_intail = 0; | ||
388 | readto = INBUFSIZE; | ||
389 | } | ||
390 | else | ||
391 | { | ||
392 | ret = recv(fd, x->sr_inbuf + x->sr_inhead, | ||
393 | readto - x->sr_inhead, 0); | ||
394 | if (ret < 0) | ||
395 | { | ||
396 | sys_sockerror("recv"); | ||
397 | if (x == sys_socketreceiver) sys_bail(1); | ||
398 | else | ||
399 | { | ||
400 | if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); | ||
401 | sys_rmpollfn(fd); | ||
402 | sys_closesocket(fd); | ||
403 | } | ||
404 | } | ||
405 | else if (ret == 0) | ||
406 | { | ||
407 | if (x == sys_socketreceiver) | ||
408 | { | ||
409 | fprintf(stderr, "pd: exiting\n"); | ||
410 | sys_bail(0); | ||
411 | } | ||
412 | else | ||
413 | { | ||
414 | post("EOF on socket %d\n", fd); | ||
415 | if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); | ||
416 | sys_rmpollfn(fd); | ||
417 | sys_closesocket(fd); | ||
418 | } | ||
419 | } | ||
420 | else | ||
421 | { | ||
422 | x->sr_inhead += ret; | ||
423 | if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; | ||
424 | while (socketreceiver_doread(x)) | ||
425 | { | ||
426 | outlet_setstacklim(); | ||
427 | if (x->sr_socketreceivefn) | ||
428 | (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); | ||
429 | else binbuf_eval(inbinbuf, 0, 0, 0); | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | |||
436 | void sys_closesocket(int fd) | ||
437 | { | ||
438 | #ifdef UNIX | ||
439 | close(fd); | ||
440 | #endif | ||
441 | #ifdef MSW | ||
442 | closesocket(fd); | ||
443 | #endif | ||
444 | } | ||
445 | |||
446 | |||
447 | void sys_gui(char *s) | ||
448 | { | ||
449 | int length = strlen(s), written = 0, res, histwas = sys_addhist(4); | ||
450 | if (sys_debuglevel & DEBUG_MESSUP) | ||
451 | fprintf(stderr, "%s", s); | ||
452 | if (sys_nogui) | ||
453 | return; | ||
454 | while (1) | ||
455 | { | ||
456 | res = send(sys_guisock, s + written, length, 0); | ||
457 | if (res < 0) | ||
458 | { | ||
459 | perror("pd output pipe"); | ||
460 | sys_bail(1); | ||
461 | } | ||
462 | else | ||
463 | { | ||
464 | written += res; | ||
465 | if (written >= length) | ||
466 | break; | ||
467 | } | ||
468 | } | ||
469 | sys_addhist(histwas); | ||
470 | } | ||
471 | |||
472 | /* LATER should do a bounds check -- but how do you get printf to do that? | ||
473 | See also rtext_senditup() in this regard */ | ||
474 | |||
475 | void sys_vgui(char *fmt, ...) | ||
476 | { | ||
477 | int result, i; | ||
478 | char buf[2048]; | ||
479 | va_list ap; | ||
480 | |||
481 | va_start(ap, fmt); | ||
482 | vsprintf(buf, fmt, ap); | ||
483 | sys_gui(buf); | ||
484 | va_end(ap); | ||
485 | } | ||
486 | |||
487 | |||
488 | #define FIRSTPORTNUM 5400 | ||
489 | |||
490 | /* -------------- signal handling for UNIX -------------- */ | ||
491 | |||
492 | #ifdef UNIX | ||
493 | typedef void (*sighandler_t)(int); | ||
494 | |||
495 | static void sys_signal(int signo, sighandler_t sigfun) | ||
496 | { | ||
497 | struct sigaction action; | ||
498 | action.sa_flags = 0; | ||
499 | action.sa_handler = sigfun; | ||
500 | memset(&action.sa_mask, 0, sizeof(action.sa_mask)); | ||
501 | #if 0 /* GG says: don't use that */ | ||
502 | action.sa_restorer = 0; | ||
503 | #endif | ||
504 | if (sigaction(signo, &action, 0) < 0) | ||
505 | perror("sigaction"); | ||
506 | } | ||
507 | |||
508 | static void sys_exithandler(int n) | ||
509 | { | ||
510 | static int trouble = 0; | ||
511 | if (!trouble) | ||
512 | { | ||
513 | trouble = 1; | ||
514 | fprintf(stderr, "Pd: signal %d\n", n); | ||
515 | sys_bail(1); | ||
516 | |||
517 | } | ||
518 | else _exit(1); | ||
519 | } | ||
520 | |||
521 | static void sys_alarmhandler(int n) | ||
522 | { | ||
523 | fprintf(stderr, "Pd: system call timed out\n"); | ||
524 | } | ||
525 | |||
526 | static void sys_huphandler(int n) | ||
527 | { | ||
528 | struct timeval timout; | ||
529 | timout.tv_sec = 0; | ||
530 | timout.tv_usec = 30000; | ||
531 | select(1, 0, 0, 0, &timout); | ||
532 | } | ||
533 | |||
534 | void sys_setalarm(int microsec) | ||
535 | { | ||
536 | struct itimerval gonzo; | ||
537 | #if 0 | ||
538 | fprintf(stderr, "timer %d\n", microsec); | ||
539 | #endif | ||
540 | gonzo.it_interval.tv_sec = 0; | ||
541 | gonzo.it_interval.tv_usec = 0; | ||
542 | gonzo.it_value.tv_sec = 0; | ||
543 | gonzo.it_value.tv_usec = microsec; | ||
544 | if (microsec) | ||
545 | sys_signal(SIGALRM, sys_alarmhandler); | ||
546 | else sys_signal(SIGALRM, SIG_IGN); | ||
547 | setitimer(ITIMER_REAL, &gonzo, 0); | ||
548 | } | ||
549 | |||
550 | #endif | ||
551 | |||
552 | #ifdef __linux__ | ||
553 | |||
554 | #if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK) | ||
555 | #include <sched.h> | ||
556 | #endif | ||
557 | |||
558 | void sys_set_priority(int higher) | ||
559 | { | ||
560 | #ifdef _POSIX_PRIORITY_SCHEDULING | ||
561 | struct sched_param par; | ||
562 | int p1 ,p2, p3; | ||
563 | p1 = sched_get_priority_min(SCHED_FIFO); | ||
564 | p2 = sched_get_priority_max(SCHED_FIFO); | ||
565 | #ifdef USEAPI_JACK | ||
566 | p3 = (higher ? p1 + 7 : p1 + 5); | ||
567 | #else | ||
568 | p3 = (higher ? p2 - 1 : p2 - 3); | ||
569 | #endif | ||
570 | par.sched_priority = p3; | ||
571 | if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) | ||
572 | fprintf(stderr, "priority %d scheduling enabled.\n", p3); | ||
573 | #endif | ||
574 | |||
575 | #ifdef _POSIX_MEMLOCK | ||
576 | if (mlockall(MCL_FUTURE) != -1) | ||
577 | fprintf(stderr, "memory locking enabled.\n"); | ||
578 | #endif | ||
579 | |||
580 | } | ||
581 | |||
582 | #endif /* __linux__ */ | ||
583 | |||
584 | static int sys_watchfd; | ||
585 | |||
586 | #ifdef __linux__ | ||
587 | void glob_ping(t_pd *dummy) | ||
588 | { | ||
589 | if (write(sys_watchfd, "\n", 1) < 1) | ||
590 | { | ||
591 | fprintf(stderr, "pd: watchdog process died\n"); | ||
592 | sys_bail(1); | ||
593 | } | ||
594 | } | ||
595 | #endif | ||
596 | |||
597 | static int defaultfontshit[] = { | ||
598 | 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28, | ||
599 | 24, 15, 28}; | ||
600 | |||
601 | int sys_startgui(const char *guidir) | ||
602 | { | ||
603 | pid_t childpid; | ||
604 | char cmdbuf[4*MAXPDSTRING]; | ||
605 | struct sockaddr_in server; | ||
606 | int msgsock; | ||
607 | char buf[15]; | ||
608 | int len = sizeof(server); | ||
609 | int ntry = 0, portno = FIRSTPORTNUM; | ||
610 | int xsock = -1; | ||
611 | #ifdef MSW | ||
612 | short version = MAKEWORD(2, 0); | ||
613 | WSADATA nobby; | ||
614 | #endif | ||
615 | #ifdef UNIX | ||
616 | int stdinpipe[2]; | ||
617 | #endif | ||
618 | /* create an empty FD poll list */ | ||
619 | sys_fdpoll = (t_fdpoll *)t_getbytes(0); | ||
620 | sys_nfdpoll = 0; | ||
621 | inbinbuf = binbuf_new(); | ||
622 | |||
623 | #ifdef UNIX | ||
624 | signal(SIGHUP, sys_huphandler); | ||
625 | signal(SIGINT, sys_exithandler); | ||
626 | signal(SIGQUIT, sys_exithandler); | ||
627 | signal(SIGILL, sys_exithandler); | ||
628 | signal(SIGIOT, sys_exithandler); | ||
629 | signal(SIGFPE, SIG_IGN); | ||
630 | /* signal(SIGILL, sys_exithandler); | ||
631 | signal(SIGBUS, sys_exithandler); | ||
632 | signal(SIGSEGV, sys_exithandler); */ | ||
633 | signal(SIGPIPE, SIG_IGN); | ||
634 | signal(SIGALRM, SIG_IGN); | ||
635 | signal(SIGTERM, SIG_IGN); | ||
636 | #if 0 /* GG says: don't use that */ | ||
637 | signal(SIGSTKFLT, sys_exithandler); | ||
638 | #endif | ||
639 | #endif | ||
640 | #ifdef MSW | ||
641 | if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup"); | ||
642 | #endif | ||
643 | |||
644 | if (sys_nogui) | ||
645 | { | ||
646 | /* fake the GUI's message giving cwd and font sizes; then | ||
647 | skip starting the GUI up. */ | ||
648 | t_atom zz[19]; | ||
649 | int i; | ||
650 | #ifdef MSW | ||
651 | if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0) | ||
652 | strcpy(cmdbuf, "."); | ||
653 | #endif | ||
654 | #ifdef UNIX | ||
655 | if (!getcwd(cmdbuf, MAXPDSTRING)) | ||
656 | strcpy(cmdbuf, "."); | ||
657 | |||
658 | #endif | ||
659 | SETSYMBOL(zz, gensym(cmdbuf)); | ||
660 | for (i = 1; i < 22; i++) | ||
661 | SETFLOAT(zz + i, defaultfontshit[i-1]); | ||
662 | SETFLOAT(zz+22,0); | ||
663 | glob_initfromgui(0, 0, 23, zz); | ||
664 | } | ||
665 | else | ||
666 | { | ||
667 | #ifdef MSW | ||
668 | char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80]; | ||
669 | int spawnret; | ||
670 | |||
671 | #endif | ||
672 | #ifdef MSW | ||
673 | char intarg; | ||
674 | #else | ||
675 | int intarg; | ||
676 | #endif | ||
677 | |||
678 | /* create a socket */ | ||
679 | xsock = socket(AF_INET, SOCK_STREAM, 0); | ||
680 | if (xsock < 0) sys_sockerror("socket"); | ||
681 | #if 0 | ||
682 | intarg = 0; | ||
683 | if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF, | ||
684 | &intarg, sizeof(intarg)) < 0) | ||
685 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
686 | intarg = 0; | ||
687 | if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF, | ||
688 | &intarg, sizeof(intarg)) < 0) | ||
689 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
690 | #endif | ||
691 | intarg = 1; | ||
692 | if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY, | ||
693 | &intarg, sizeof(intarg)) < 0) | ||
694 | #ifndef MSW | ||
695 | post("setsockopt (TCP_NODELAY) failed\n") | ||
696 | #endif | ||
697 | ; | ||
698 | |||
699 | |||
700 | server.sin_family = AF_INET; | ||
701 | server.sin_addr.s_addr = INADDR_ANY; | ||
702 | |||
703 | /* assign server port number */ | ||
704 | server.sin_port = htons((unsigned short)portno); | ||
705 | |||
706 | /* name the socket */ | ||
707 | while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0) | ||
708 | { | ||
709 | #ifdef MSW | ||
710 | int err = WSAGetLastError(); | ||
711 | #endif | ||
712 | #ifdef UNIX | ||
713 | int err = errno; | ||
714 | #endif | ||
715 | if ((ntry++ > 20) || (err != EADDRINUSE)) | ||
716 | { | ||
717 | perror("bind"); | ||
718 | fprintf(stderr, | ||
719 | "Pd needs your machine to be configured with\n"); | ||
720 | fprintf(stderr, | ||
721 | "'networking' turned on (see Pd's html doc for details.)\n"); | ||
722 | exit(1); | ||
723 | } | ||
724 | portno++; | ||
725 | server.sin_port = htons((unsigned short)(portno)); | ||
726 | } | ||
727 | |||
728 | if (sys_verbose) fprintf(stderr, "port %d\n", portno); | ||
729 | |||
730 | sys_socketreceiver = socketreceiver_new(0, 0, 0, 0); | ||
731 | |||
732 | #ifdef UNIX | ||
733 | childpid = fork(); | ||
734 | if (childpid < 0) | ||
735 | { | ||
736 | if (errno) perror("sys_startgui"); | ||
737 | else fprintf(stderr, "sys_startgui failed\n"); | ||
738 | return (1); | ||
739 | } | ||
740 | else if (!childpid) /* we're the child */ | ||
741 | { | ||
742 | seteuid(getuid()); /* lose setuid priveliges */ | ||
743 | #ifndef MACOSX | ||
744 | /* the wish process in Unix will make a wish shell and | ||
745 | read/write standard in and out unless we close the | ||
746 | file descriptors. Somehow this doesn't make the MAC OSX | ||
747 | version of Wish happy...*/ | ||
748 | if (pipe(stdinpipe) < 0) | ||
749 | sys_sockerror("pipe"); | ||
750 | else | ||
751 | { | ||
752 | if (stdinpipe[0] != 0) | ||
753 | { | ||
754 | close (0); | ||
755 | dup2(stdinpipe[0], 0); | ||
756 | close(stdinpipe[0]); | ||
757 | } | ||
758 | } | ||
759 | #endif | ||
760 | if (!sys_guicmd) | ||
761 | { | ||
762 | #ifdef MACOSX | ||
763 | char *homedir = getenv("HOME"), filename[250]; | ||
764 | struct stat statbuf; | ||
765 | if (!homedir || strlen(homedir) > 150) | ||
766 | goto nohomedir; | ||
767 | sprintf(filename, | ||
768 | "%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell", | ||
769 | homedir); | ||
770 | if (stat(filename, &statbuf) >= 0) | ||
771 | goto foundit; | ||
772 | sprintf(filename, | ||
773 | "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell", | ||
774 | homedir); | ||
775 | if (stat(filename, &statbuf) >= 0) | ||
776 | goto foundit; | ||
777 | nohomedir: | ||
778 | strcpy(filename, | ||
779 | "/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell"); | ||
780 | if (stat(filename, &statbuf) >= 0) | ||
781 | goto foundit; | ||
782 | strcpy(filename, | ||
783 | "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell"); | ||
784 | foundit: | ||
785 | sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno); | ||
786 | #else | ||
787 | sprintf(cmdbuf, | ||
788 | "TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \ | ||
789 | \"%s/pd-gui\" %d\n", | ||
790 | sys_libdir->s_name, sys_libdir->s_name, guidir, portno); | ||
791 | #endif | ||
792 | sys_guicmd = cmdbuf; | ||
793 | } | ||
794 | if (sys_verbose) fprintf(stderr, "%s", sys_guicmd); | ||
795 | execl("/bin/sh", "sh", "-c", sys_guicmd, 0); | ||
796 | perror("pd: exec"); | ||
797 | _exit(1); | ||
798 | } | ||
799 | #endif /* UNIX */ | ||
800 | |||
801 | #ifdef MSW | ||
802 | /* in MSW land "guipath" is unused; we just do everything from | ||
803 | the libdir. */ | ||
804 | /* fprintf(stderr, "%s\n", sys_libdir->s_name); */ | ||
805 | |||
806 | strcpy(scriptbuf, "\""); | ||
807 | strcat(scriptbuf, sys_libdir->s_name); | ||
808 | strcat(scriptbuf, "/" PDBINDIR "pd.tk\""); | ||
809 | sys_bashfilename(scriptbuf, scriptbuf); | ||
810 | |||
811 | sprintf(portbuf, "%d", portno); | ||
812 | |||
813 | strcpy(wishbuf, sys_libdir->s_name); | ||
814 | strcat(wishbuf, "/" PDBINDIR WISHAPP); | ||
815 | sys_bashfilename(wishbuf, wishbuf); | ||
816 | |||
817 | spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0); | ||
818 | if (spawnret < 0) | ||
819 | { | ||
820 | perror("spawnl"); | ||
821 | fprintf(stderr, "%s: couldn't load TCL\n", wishbuf); | ||
822 | exit(1); | ||
823 | } | ||
824 | |||
825 | #endif /* MSW */ | ||
826 | } | ||
827 | |||
828 | #ifdef __linux__ | ||
829 | /* now that we've spun off the child process we can promote | ||
830 | our process's priority, if we happen to be root. */ | ||
831 | if (sys_hipriority) | ||
832 | { | ||
833 | if (!getuid() || !geteuid()) | ||
834 | { | ||
835 | /* To prevent lockup, we fork off a watchdog process with | ||
836 | higher real-time priority than ours. The GUI has to send | ||
837 | a stream of ping messages to the watchdog THROUGH the Pd | ||
838 | process which has to pick them up from the GUI and forward | ||
839 | them. If any of these things aren't happening the watchdog | ||
840 | starts sending "stop" and "cont" signals to the Pd process | ||
841 | to make it timeshare with the rest of the system. (Version | ||
842 | 0.33P2 : if there's no GUI, the watchdog pinging is done | ||
843 | from the scheduler idle routine in this process instead.) */ | ||
844 | |||
845 | int pipe9[2], watchpid; | ||
846 | if (pipe(pipe9) < 0) | ||
847 | { | ||
848 | seteuid(getuid()); /* lose setuid priveliges */ | ||
849 | sys_sockerror("pipe"); | ||
850 | return (1); | ||
851 | } | ||
852 | watchpid = fork(); | ||
853 | if (watchpid < 0) | ||
854 | { | ||
855 | seteuid(getuid()); /* lose setuid priveliges */ | ||
856 | if (errno) | ||
857 | perror("sys_startgui"); | ||
858 | else fprintf(stderr, "sys_startgui failed\n"); | ||
859 | return (1); | ||
860 | } | ||
861 | else if (!watchpid) /* we're the child */ | ||
862 | { | ||
863 | sys_set_priority(1); | ||
864 | seteuid(getuid()); /* lose setuid priveliges */ | ||
865 | if (pipe9[1] != 0) | ||
866 | { | ||
867 | dup2(pipe9[0], 0); | ||
868 | close(pipe9[0]); | ||
869 | } | ||
870 | close(pipe9[1]); | ||
871 | |||
872 | sprintf(cmdbuf, "%s/pd-watchdog\n", guidir); | ||
873 | if (sys_verbose) fprintf(stderr, "%s", cmdbuf); | ||
874 | execl("/bin/sh", "sh", "-c", cmdbuf, 0); | ||
875 | perror("pd: exec"); | ||
876 | _exit(1); | ||
877 | } | ||
878 | else /* we're the parent */ | ||
879 | { | ||
880 | sys_set_priority(0); | ||
881 | seteuid(getuid()); /* lose setuid priveliges */ | ||
882 | close(pipe9[0]); | ||
883 | sys_watchfd = pipe9[1]; | ||
884 | /* We also have to start the ping loop in the GUI; | ||
885 | this is done later when the socket is open. */ | ||
886 | } | ||
887 | } | ||
888 | else | ||
889 | { | ||
890 | post("realtime setting failed because not root\n"); | ||
891 | sys_hipriority = 0; | ||
892 | } | ||
893 | } | ||
894 | |||
895 | seteuid(getuid()); /* lose setuid priveliges */ | ||
896 | #endif /* __linux__ */ | ||
897 | |||
898 | #ifdef MSW | ||
899 | if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) | ||
900 | fprintf(stderr, "pd: couldn't set high priority class\n"); | ||
901 | #endif | ||
902 | #ifdef MACOSX | ||
903 | if (sys_hipriority) | ||
904 | { | ||
905 | struct sched_param param; | ||
906 | int policy = SCHED_RR; | ||
907 | int err; | ||
908 | param.sched_priority = 80; // adjust 0 : 100 | ||
909 | |||
910 | err = pthread_setschedparam(pthread_self(), policy, ¶m); | ||
911 | if (err) | ||
912 | post("warning: high priority scheduling failed\n"); | ||
913 | } | ||
914 | #endif /* MACOSX */ | ||
915 | |||
916 | if (!sys_nogui) | ||
917 | { | ||
918 | char buf[256]; | ||
919 | if (sys_verbose) | ||
920 | fprintf(stderr, "Waiting for connection request... \n"); | ||
921 | if (listen(xsock, 5) < 0) sys_sockerror("listen"); | ||
922 | |||
923 | sys_guisock = accept(xsock, (struct sockaddr *) &server, &len); | ||
924 | #ifdef OOPS | ||
925 | close(xsock); | ||
926 | #endif | ||
927 | if (sys_guisock < 0) sys_sockerror("accept"); | ||
928 | sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read, | ||
929 | sys_socketreceiver); | ||
930 | |||
931 | if (sys_verbose) | ||
932 | fprintf(stderr, "... connected\n"); | ||
933 | |||
934 | /* here is where we start the pinging. */ | ||
935 | #ifdef __linux__ | ||
936 | if (sys_hipriority) | ||
937 | sys_gui("pdtk_watchdog\n"); | ||
938 | #endif | ||
939 | sys_get_audio_apis(buf); | ||
940 | sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf); | ||
941 | } | ||
942 | if (sys_stdin) { | ||
943 | set_keypress(); | ||
944 | _ss = gensym("stdin"); | ||
945 | sys_addpollfn(1, (t_fdpollfn) stdin_read,NULL); | ||
946 | } | ||
947 | return (0); | ||
948 | |||
949 | } | ||
950 | |||
951 | |||
952 | static int sys_poll_togui(void) | ||
953 | { | ||
954 | /* LATER use this to flush output buffer to gui */ | ||
955 | return (0); | ||
956 | } | ||
957 | |||
958 | int sys_pollgui(void) | ||
959 | { | ||
960 | return (sys_domicrosleep(0, 1) || sys_poll_togui()); | ||
961 | } | ||
962 | |||
963 | |||
964 | /* T.Grill - import clean quit function */ | ||
965 | extern void sys_exit(void); | ||
966 | |||
967 | /* This is called when something bad has happened, like a segfault. | ||
968 | Call glob_quit() below to exit cleanly. | ||
969 | LATER try to save dirty documents even in the bad case. */ | ||
970 | void sys_bail(int n) | ||
971 | { | ||
972 | static int reentered = 0; | ||
973 | reset_keypress(); | ||
974 | if (!reentered) | ||
975 | { | ||
976 | reentered = 1; | ||
977 | #ifndef __linux /* sys_close_audio() hangs if you're in a signal? */ | ||
978 | fprintf(stderr, "closing audio...\n"); | ||
979 | sys_close_audio(); | ||
980 | fprintf(stderr, "closing MIDI...\n"); | ||
981 | sys_close_midi(); | ||
982 | fprintf(stderr, "... done.\n"); | ||
983 | #endif | ||
984 | exit(1); | ||
985 | } | ||
986 | else _exit(n); | ||
987 | } | ||
988 | |||
989 | void glob_quit(void *dummy) | ||
990 | { | ||
991 | sys_vgui("exit\n"); | ||
992 | if (!sys_nogui) | ||
993 | { | ||
994 | close(sys_guisock); | ||
995 | sys_rmpollfn(sys_guisock); | ||
996 | } | ||
997 | reset_keypress(); | ||
998 | sys_bail(0); | ||
999 | } | ||
1000 | |||
1001 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
1002 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
1003 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
1004 | |||
1005 | /* Pd side of the Pd/Pd-gui interface. Also, some system interface routines | ||
1006 | that didn't really belong anywhere. */ | ||
1007 | |||
1008 | #include "m_pd.h" | ||
1009 | #include "s_stuff.h" | ||
1010 | #include "m_imp.h" | ||
1011 | #ifdef UNIX | ||
1012 | #include <unistd.h> | ||
1013 | #include <sys/socket.h> | ||
1014 | #include <netinet/in.h> | ||
1015 | #include <netinet/tcp.h> | ||
1016 | #include <netdb.h> | ||
1017 | #include <stdlib.h> | ||
1018 | #include <sys/time.h> | ||
1019 | #include <sys/mman.h> | ||
1020 | #endif | ||
1021 | #ifdef HAVE_BSTRING_H | ||
1022 | #include <bstring.h> | ||
1023 | #endif | ||
1024 | #ifdef MSW | ||
1025 | #include <io.h> | ||
1026 | #include <fcntl.h> | ||
1027 | #include <process.h> | ||
1028 | #include <winsock.h> | ||
1029 | typedef int pid_t; | ||
1030 | #define EADDRINUSE WSAEADDRINUSE | ||
1031 | #endif | ||
1032 | #include <stdarg.h> | ||
1033 | #include <signal.h> | ||
1034 | #include <fcntl.h> | ||
1035 | #include <errno.h> | ||
1036 | #include <string.h> | ||
1037 | #include <stdio.h> | ||
1038 | |||
1039 | #ifdef MACOSX | ||
1040 | #include <sys/types.h> | ||
1041 | #include <sys/stat.h> | ||
1042 | #include <pthread.h> | ||
1043 | #else | ||
1044 | #include <stdlib.h> | ||
1045 | #endif | ||
1046 | |||
1047 | #define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */ | ||
1048 | #define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */ | ||
1049 | |||
1050 | /* T.Grill - make it a _little_ more adaptable... */ | ||
1051 | #ifndef PDBINDIR | ||
1052 | #define PDBINDIR "bin/" | ||
1053 | #endif | ||
1054 | |||
1055 | #ifndef WISHAPP | ||
1056 | #define WISHAPP "wish83.exe" | ||
1057 | #endif | ||
1058 | |||
1059 | extern char pd_version[]; | ||
1060 | |||
1061 | typedef struct _fdpoll | ||
1062 | { | ||
1063 | int fdp_fd; | ||
1064 | t_fdpollfn fdp_fn; | ||
1065 | void *fdp_ptr; | ||
1066 | } t_fdpoll; | ||
1067 | |||
1068 | #define INBUFSIZE 4096 | ||
1069 | |||
1070 | struct _socketreceiver | ||
1071 | { | ||
1072 | char *sr_inbuf; | ||
1073 | int sr_inhead; | ||
1074 | int sr_intail; | ||
1075 | void *sr_owner; | ||
1076 | int sr_udp; | ||
1077 | t_socketnotifier sr_notifier; | ||
1078 | t_socketreceivefn sr_socketreceivefn; | ||
1079 | }; | ||
1080 | |||
1081 | static int sys_nfdpoll; | ||
1082 | static t_fdpoll *sys_fdpoll; | ||
1083 | static int sys_maxfd; | ||
1084 | static int sys_guisock; | ||
1085 | |||
1086 | static t_binbuf *inbinbuf; | ||
1087 | static t_socketreceiver *sys_socketreceiver; | ||
1088 | extern int sys_addhist(int phase); | ||
1089 | |||
1090 | #ifdef MSW | ||
1091 | static LARGE_INTEGER nt_inittime; | ||
1092 | static double nt_freq = 0; | ||
1093 | |||
1094 | static void sys_initntclock(void) | ||
1095 | { | ||
1096 | LARGE_INTEGER f1; | ||
1097 | LARGE_INTEGER now; | ||
1098 | QueryPerformanceCounter(&now); | ||
1099 | if (!QueryPerformanceFrequency(&f1)) | ||
1100 | { | ||
1101 | fprintf(stderr, "pd: QueryPerformanceFrequency failed\n"); | ||
1102 | f1.QuadPart = 1; | ||
1103 | } | ||
1104 | nt_freq = f1.QuadPart; | ||
1105 | nt_inittime = now; | ||
1106 | } | ||
1107 | |||
1108 | #if 0 | ||
1109 | /* this is a version you can call if you did the QueryPerformanceCounter | ||
1110 | call yourself. Necessary for time tagging incoming MIDI at interrupt | ||
1111 | level, for instance; but we're not doing that just now. */ | ||
1112 | |||
1113 | double nt_tixtotime(LARGE_INTEGER *dumbass) | ||
1114 | { | ||
1115 | if (nt_freq == 0) sys_initntclock(); | ||
1116 | return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq); | ||
1117 | } | ||
1118 | #endif | ||
1119 | #endif /* MSW */ | ||
1120 | |||
1121 | /* get "real time" in seconds; take the | ||
1122 | first time we get called as a reference time of zero. */ | ||
1123 | t_time sys_getrealtime(void) | ||
1124 | { | ||
1125 | #ifdef UNIX | ||
1126 | static struct timeval then; | ||
1127 | struct timeval now; | ||
1128 | gettimeofday(&now, 0); | ||
1129 | if (then.tv_sec == 0 && then.tv_usec == 0) then = now; | ||
1130 | return (now.tv_sec - then.tv_sec)*1000000 + | ||
1131 | (now.tv_usec - then.tv_usec); | ||
1132 | #endif | ||
1133 | #ifdef MSW | ||
1134 | LARGE_INTEGER now; | ||
1135 | QueryPerformanceCounter(&now); | ||
1136 | if (nt_freq == 0) sys_initntclock(); | ||
1137 | return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq); | ||
1138 | #endif | ||
1139 | } | ||
1140 | |||
1141 | void sys_sockerror(char *s) | ||
1142 | { | ||
1143 | #ifdef MSW | ||
1144 | int err = WSAGetLastError(); | ||
1145 | if (err == 10054) return; | ||
1146 | else if (err == 10044) | ||
1147 | { | ||
1148 | fprintf(stderr, | ||
1149 | "Warning: you might not have TCP/IP \"networking\" turned on\n"); | ||
1150 | fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n"); | ||
1151 | } | ||
1152 | #endif | ||
1153 | #ifdef UNIX | ||
1154 | int err = errno; | ||
1155 | #endif | ||
1156 | fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err); | ||
1157 | } | ||
1158 | |||
1159 | void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr) | ||
1160 | { | ||
1161 | int nfd = sys_nfdpoll; | ||
1162 | int size = nfd * sizeof(t_fdpoll); | ||
1163 | t_fdpoll *fp; | ||
1164 | sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, | ||
1165 | size + sizeof(t_fdpoll)); | ||
1166 | fp = sys_fdpoll + nfd; | ||
1167 | fp->fdp_fd = fd; | ||
1168 | fp->fdp_fn = fn; | ||
1169 | fp->fdp_ptr = ptr; | ||
1170 | sys_nfdpoll = nfd + 1; | ||
1171 | if (fd >= sys_maxfd) sys_maxfd = fd + 1; | ||
1172 | } | ||
1173 | |||
1174 | void sys_rmpollfn(int fd) | ||
1175 | { | ||
1176 | int nfd = sys_nfdpoll; | ||
1177 | int i, size = nfd * sizeof(t_fdpoll); | ||
1178 | t_fdpoll *fp; | ||
1179 | for (i = nfd, fp = sys_fdpoll; i--; fp++) | ||
1180 | { | ||
1181 | if (fp->fdp_fd == fd) | ||
1182 | { | ||
1183 | while (i--) | ||
1184 | { | ||
1185 | fp[0] = fp[1]; | ||
1186 | fp++; | ||
1187 | } | ||
1188 | sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, | ||
1189 | size - sizeof(t_fdpoll)); | ||
1190 | sys_nfdpoll = nfd - 1; | ||
1191 | return; | ||
1192 | } | ||
1193 | } | ||
1194 | post("warning: %d removed from poll list but not found", fd); | ||
1195 | } | ||
1196 | |||
1197 | static int sys_domicrosleep(int microsec, int pollem) | ||
1198 | { | ||
1199 | struct timeval timout; | ||
1200 | int i, didsomething = 0; | ||
1201 | t_fdpoll *fp; | ||
1202 | timout.tv_sec = 0; | ||
1203 | timout.tv_usec = microsec; | ||
1204 | if (pollem) | ||
1205 | { | ||
1206 | fd_set readset, writeset, exceptset; | ||
1207 | FD_ZERO(&writeset); | ||
1208 | FD_ZERO(&readset); | ||
1209 | FD_ZERO(&exceptset); | ||
1210 | for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++) | ||
1211 | FD_SET(fp->fdp_fd, &readset); | ||
1212 | select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout); | ||
1213 | for (i = 0; i < sys_nfdpoll; i++) | ||
1214 | if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset)) | ||
1215 | { | ||
1216 | (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd); | ||
1217 | didsomething = 1; | ||
1218 | } | ||
1219 | return (didsomething); | ||
1220 | } | ||
1221 | else | ||
1222 | { | ||
1223 | select(0, 0, 0, 0, &timout); | ||
1224 | return (0); | ||
1225 | } | ||
1226 | } | ||
1227 | |||
1228 | void sys_microsleep(int microsec) | ||
1229 | { | ||
1230 | sys_domicrosleep(microsec, 1); | ||
1231 | } | ||
1232 | |||
1233 | t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier, | ||
1234 | t_socketreceivefn socketreceivefn, int udp) | ||
1235 | { | ||
1236 | t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x)); | ||
1237 | x->sr_inhead = x->sr_intail = 0; | ||
1238 | x->sr_owner = owner; | ||
1239 | x->sr_notifier = notifier; | ||
1240 | x->sr_socketreceivefn = socketreceivefn; | ||
1241 | x->sr_udp = udp; | ||
1242 | if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");; | ||
1243 | return (x); | ||
1244 | } | ||
1245 | |||
1246 | void socketreceiver_free(t_socketreceiver *x) | ||
1247 | { | ||
1248 | free(x->sr_inbuf); | ||
1249 | freebytes(x, sizeof(*x)); | ||
1250 | } | ||
1251 | |||
1252 | /* this is in a separately called subroutine so that the buffer isn't | ||
1253 | sitting on the stack while the messages are getting passed. */ | ||
1254 | static int socketreceiver_doread(t_socketreceiver *x) | ||
1255 | { | ||
1256 | char messbuf[INBUFSIZE], *bp = messbuf; | ||
1257 | int indx; | ||
1258 | int inhead = x->sr_inhead; | ||
1259 | int intail = x->sr_intail; | ||
1260 | char *inbuf = x->sr_inbuf; | ||
1261 | if (intail == inhead) return (0); | ||
1262 | for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) | ||
1263 | { | ||
1264 | /* if we hit a semi that isn't preceeded by a \, it's a message | ||
1265 | boundary. LATER we should deal with the possibility that the | ||
1266 | preceeding \ might itself be escaped! */ | ||
1267 | char c = *bp++ = inbuf[indx]; | ||
1268 | if (c == ';' && (!indx || inbuf[indx-1] != '\\')) | ||
1269 | { | ||
1270 | intail = (indx+1)&(INBUFSIZE-1); | ||
1271 | binbuf_text(inbinbuf, messbuf, bp - messbuf); | ||
1272 | if (sys_debuglevel & DEBUG_MESSDOWN) | ||
1273 | { | ||
1274 | write(2, messbuf, bp - messbuf); | ||
1275 | write(2, "\n", 1); | ||
1276 | } | ||
1277 | x->sr_inhead = inhead; | ||
1278 | x->sr_intail = intail; | ||
1279 | return (1); | ||
1280 | } | ||
1281 | } | ||
1282 | return (0); | ||
1283 | } | ||
1284 | |||
1285 | static void socketreceiver_getudp(t_socketreceiver *x, int fd) | ||
1286 | { | ||
1287 | char buf[INBUFSIZE+1]; | ||
1288 | int ret = recv(fd, buf, INBUFSIZE, 0); | ||
1289 | if (ret < 0) | ||
1290 | { | ||
1291 | sys_sockerror("recv"); | ||
1292 | sys_rmpollfn(fd); | ||
1293 | sys_closesocket(fd); | ||
1294 | } | ||
1295 | else if (ret > 0) | ||
1296 | { | ||
1297 | buf[ret] = 0; | ||
1298 | #if 0 | ||
1299 | post("%s", buf); | ||
1300 | #endif | ||
1301 | if (buf[ret-1] != '\n') | ||
1302 | { | ||
1303 | #if 0 | ||
1304 | buf[ret] = 0; | ||
1305 | error("dropped bad buffer %s\n", buf); | ||
1306 | #endif | ||
1307 | } | ||
1308 | else | ||
1309 | { | ||
1310 | char *semi = strchr(buf, ';'); | ||
1311 | if (semi) | ||
1312 | *semi = 0; | ||
1313 | binbuf_text(inbinbuf, buf, strlen(buf)); | ||
1314 | outlet_setstacklim(); | ||
1315 | if (x->sr_socketreceivefn) | ||
1316 | (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); | ||
1317 | else bug("socketreceiver_getudp"); | ||
1318 | } | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | |||
1323 | |||
1324 | #include <termios.h> | ||
1325 | #include <string.h> | ||
1326 | |||
1327 | static struct termios stored_settings; | ||
1328 | EXTERN int sys_stdin; | ||
1329 | |||
1330 | void set_keypress(void) | ||
1331 | { | ||
1332 | struct termios new_settings; | ||
1333 | |||
1334 | tcgetattr(0,&stored_settings); | ||
1335 | |||
1336 | new_settings = stored_settings; | ||
1337 | |||
1338 | /* Disable canonical mode, and set buffer size to 1 byte */ | ||
1339 | new_settings.c_lflag &= (~ICANON); | ||
1340 | new_settings.c_cc[VTIME] = 0; | ||
1341 | new_settings.c_cc[VMIN] = 1; | ||
1342 | |||
1343 | /* echo off */ | ||
1344 | new_settings.c_lflag &= (~ECHO); | ||
1345 | |||
1346 | tcsetattr(0,TCSANOW,&new_settings); | ||
1347 | return; | ||
1348 | } | ||
1349 | |||
1350 | void reset_keypress(void) | ||
1351 | { | ||
1352 | if (sys_stdin) | ||
1353 | tcsetattr(0,TCSANOW,&stored_settings); | ||
1354 | return; | ||
1355 | } | ||
1356 | |||
1357 | static t_symbol* _ss; | ||
1358 | |||
1359 | |||
1360 | void stdin_read(t_socketreceiver *x, int fd) { | ||
1361 | static char input[256]; | ||
1362 | |||
1363 | char* in; | ||
1364 | int got; | ||
1365 | |||
1366 | got = read(fd,input,256); | ||
1367 | in = input; | ||
1368 | while (got-- && _ss->s_thing) | ||
1369 | pd_float(_ss->s_thing,(float)*in++); | ||
1370 | } | ||
1371 | |||
1372 | void socketreceiver_read(t_socketreceiver *x, int fd) | ||
1373 | { | ||
1374 | if (x->sr_udp) /* UDP ("datagram") socket protocol */ | ||
1375 | socketreceiver_getudp(x, fd); | ||
1376 | else /* TCP ("streaming") socket protocol */ | ||
1377 | { | ||
1378 | char *semi; | ||
1379 | int readto = | ||
1380 | (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); | ||
1381 | int ret; | ||
1382 | |||
1383 | /* the input buffer might be full. If so, drop the whole thing */ | ||
1384 | if (readto == x->sr_inhead) | ||
1385 | { | ||
1386 | fprintf(stderr, "pd: dropped message from gui\n"); | ||
1387 | x->sr_inhead = x->sr_intail = 0; | ||
1388 | readto = INBUFSIZE; | ||
1389 | } | ||
1390 | else | ||
1391 | { | ||
1392 | ret = recv(fd, x->sr_inbuf + x->sr_inhead, | ||
1393 | readto - x->sr_inhead, 0); | ||
1394 | if (ret < 0) | ||
1395 | { | ||
1396 | sys_sockerror("recv"); | ||
1397 | if (x == sys_socketreceiver) sys_bail(1); | ||
1398 | else | ||
1399 | { | ||
1400 | if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); | ||
1401 | sys_rmpollfn(fd); | ||
1402 | sys_closesocket(fd); | ||
1403 | } | ||
1404 | } | ||
1405 | else if (ret == 0) | ||
1406 | { | ||
1407 | if (x == sys_socketreceiver) | ||
1408 | { | ||
1409 | fprintf(stderr, "pd: exiting\n"); | ||
1410 | sys_bail(0); | ||
1411 | } | ||
1412 | else | ||
1413 | { | ||
1414 | post("EOF on socket %d\n", fd); | ||
1415 | if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); | ||
1416 | sys_rmpollfn(fd); | ||
1417 | sys_closesocket(fd); | ||
1418 | } | ||
1419 | } | ||
1420 | else | ||
1421 | { | ||
1422 | x->sr_inhead += ret; | ||
1423 | if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; | ||
1424 | while (socketreceiver_doread(x)) | ||
1425 | { | ||
1426 | outlet_setstacklim(); | ||
1427 | if (x->sr_socketreceivefn) | ||
1428 | (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); | ||
1429 | else binbuf_eval(inbinbuf, 0, 0, 0); | ||
1430 | } | ||
1431 | } | ||
1432 | } | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | void sys_closesocket(int fd) | ||
1437 | { | ||
1438 | #ifdef UNIX | ||
1439 | close(fd); | ||
1440 | #endif | ||
1441 | #ifdef MSW | ||
1442 | closesocket(fd); | ||
1443 | #endif | ||
1444 | } | ||
1445 | |||
1446 | |||
1447 | void sys_gui(char *s) | ||
1448 | { | ||
1449 | int length = strlen(s), written = 0, res, histwas = sys_addhist(4); | ||
1450 | if (sys_debuglevel & DEBUG_MESSUP) | ||
1451 | fprintf(stderr, "%s", s); | ||
1452 | if (sys_nogui) | ||
1453 | return; | ||
1454 | while (1) | ||
1455 | { | ||
1456 | res = send(sys_guisock, s + written, length, 0); | ||
1457 | if (res < 0) | ||
1458 | { | ||
1459 | perror("pd output pipe"); | ||
1460 | sys_bail(1); | ||
1461 | } | ||
1462 | else | ||
1463 | { | ||
1464 | written += res; | ||
1465 | if (written >= length) | ||
1466 | break; | ||
1467 | } | ||
1468 | } | ||
1469 | sys_addhist(histwas); | ||
1470 | } | ||
1471 | |||
1472 | /* LATER should do a bounds check -- but how do you get printf to do that? | ||
1473 | See also rtext_senditup() in this regard */ | ||
1474 | |||
1475 | void sys_vgui(char *fmt, ...) | ||
1476 | { | ||
1477 | int result, i; | ||
1478 | char buf[2048]; | ||
1479 | va_list ap; | ||
1480 | |||
1481 | va_start(ap, fmt); | ||
1482 | vsprintf(buf, fmt, ap); | ||
1483 | sys_gui(buf); | ||
1484 | va_end(ap); | ||
1485 | } | ||
1486 | |||
1487 | |||
1488 | #define FIRSTPORTNUM 5400 | ||
1489 | |||
1490 | /* -------------- signal handling for UNIX -------------- */ | ||
1491 | |||
1492 | #ifdef UNIX | ||
1493 | typedef void (*sighandler_t)(int); | ||
1494 | |||
1495 | static void sys_signal(int signo, sighandler_t sigfun) | ||
1496 | { | ||
1497 | struct sigaction action; | ||
1498 | action.sa_flags = 0; | ||
1499 | action.sa_handler = sigfun; | ||
1500 | memset(&action.sa_mask, 0, sizeof(action.sa_mask)); | ||
1501 | #if 0 /* GG says: don't use that */ | ||
1502 | action.sa_restorer = 0; | ||
1503 | #endif | ||
1504 | if (sigaction(signo, &action, 0) < 0) | ||
1505 | perror("sigaction"); | ||
1506 | } | ||
1507 | |||
1508 | static void sys_exithandler(int n) | ||
1509 | { | ||
1510 | static int trouble = 0; | ||
1511 | if (!trouble) | ||
1512 | { | ||
1513 | trouble = 1; | ||
1514 | fprintf(stderr, "Pd: signal %d\n", n); | ||
1515 | sys_bail(1); | ||
1516 | |||
1517 | } | ||
1518 | else _exit(1); | ||
1519 | } | ||
1520 | |||
1521 | static void sys_alarmhandler(int n) | ||
1522 | { | ||
1523 | fprintf(stderr, "Pd: system call timed out\n"); | ||
1524 | } | ||
1525 | |||
1526 | static void sys_huphandler(int n) | ||
1527 | { | ||
1528 | struct timeval timout; | ||
1529 | timout.tv_sec = 0; | ||
1530 | timout.tv_usec = 30000; | ||
1531 | select(1, 0, 0, 0, &timout); | ||
1532 | } | ||
1533 | |||
1534 | void sys_setalarm(int microsec) | ||
1535 | { | ||
1536 | struct itimerval gonzo; | ||
1537 | #if 0 | ||
1538 | fprintf(stderr, "timer %d\n", microsec); | ||
1539 | #endif | ||
1540 | gonzo.it_interval.tv_sec = 0; | ||
1541 | gonzo.it_interval.tv_usec = 0; | ||
1542 | gonzo.it_value.tv_sec = 0; | ||
1543 | gonzo.it_value.tv_usec = microsec; | ||
1544 | if (microsec) | ||
1545 | sys_signal(SIGALRM, sys_alarmhandler); | ||
1546 | else sys_signal(SIGALRM, SIG_IGN); | ||
1547 | setitimer(ITIMER_REAL, &gonzo, 0); | ||
1548 | } | ||
1549 | |||
1550 | #endif | ||
1551 | |||
1552 | #ifdef __linux__ | ||
1553 | |||
1554 | #if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK) | ||
1555 | #include <sched.h> | ||
1556 | #endif | ||
1557 | |||
1558 | void sys_set_priority(int higher) | ||
1559 | { | ||
1560 | #ifdef _POSIX_PRIORITY_SCHEDULING | ||
1561 | struct sched_param par; | ||
1562 | int p1 ,p2, p3; | ||
1563 | p1 = sched_get_priority_min(SCHED_FIFO); | ||
1564 | p2 = sched_get_priority_max(SCHED_FIFO); | ||
1565 | #ifdef USEAPI_JACK | ||
1566 | p3 = (higher ? p1 + 7 : p1 + 5); | ||
1567 | #else | ||
1568 | p3 = (higher ? p2 - 1 : p2 - 3); | ||
1569 | #endif | ||
1570 | par.sched_priority = p3; | ||
1571 | if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) | ||
1572 | fprintf(stderr, "priority %d scheduling enabled.\n", p3); | ||
1573 | #endif | ||
1574 | |||
1575 | #ifdef _POSIX_MEMLOCK | ||
1576 | if (mlockall(MCL_FUTURE) != -1) | ||
1577 | fprintf(stderr, "memory locking enabled.\n"); | ||
1578 | #endif | ||
1579 | |||
1580 | } | ||
1581 | |||
1582 | #endif /* __linux__ */ | ||
1583 | |||
1584 | static int sys_watchfd; | ||
1585 | |||
1586 | #ifdef __linux__ | ||
1587 | void glob_ping(t_pd *dummy) | ||
1588 | { | ||
1589 | if (write(sys_watchfd, "\n", 1) < 1) | ||
1590 | { | ||
1591 | fprintf(stderr, "pd: watchdog process died\n"); | ||
1592 | sys_bail(1); | ||
1593 | } | ||
1594 | } | ||
1595 | #endif | ||
1596 | |||
1597 | static int defaultfontshit[] = { | ||
1598 | 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28, | ||
1599 | 24, 15, 28}; | ||
1600 | |||
1601 | int sys_startgui(const char *guidir) | ||
1602 | { | ||
1603 | pid_t childpid; | ||
1604 | char cmdbuf[4*MAXPDSTRING]; | ||
1605 | struct sockaddr_in server; | ||
1606 | int msgsock; | ||
1607 | char buf[15]; | ||
1608 | int len = sizeof(server); | ||
1609 | int ntry = 0, portno = FIRSTPORTNUM; | ||
1610 | int xsock = -1; | ||
1611 | #ifdef MSW | ||
1612 | short version = MAKEWORD(2, 0); | ||
1613 | WSADATA nobby; | ||
1614 | #endif | ||
1615 | #ifdef UNIX | ||
1616 | int stdinpipe[2]; | ||
1617 | #endif | ||
1618 | /* create an empty FD poll list */ | ||
1619 | sys_fdpoll = (t_fdpoll *)t_getbytes(0); | ||
1620 | sys_nfdpoll = 0; | ||
1621 | inbinbuf = binbuf_new(); | ||
1622 | |||
1623 | #ifdef UNIX | ||
1624 | signal(SIGHUP, sys_huphandler); | ||
1625 | signal(SIGINT, sys_exithandler); | ||
1626 | signal(SIGQUIT, sys_exithandler); | ||
1627 | signal(SIGILL, sys_exithandler); | ||
1628 | signal(SIGIOT, sys_exithandler); | ||
1629 | signal(SIGFPE, SIG_IGN); | ||
1630 | /* signal(SIGILL, sys_exithandler); | ||
1631 | signal(SIGBUS, sys_exithandler); | ||
1632 | signal(SIGSEGV, sys_exithandler); */ | ||
1633 | signal(SIGPIPE, SIG_IGN); | ||
1634 | signal(SIGALRM, SIG_IGN); | ||
1635 | signal(SIGTERM, SIG_IGN); | ||
1636 | #if 0 /* GG says: don't use that */ | ||
1637 | signal(SIGSTKFLT, sys_exithandler); | ||
1638 | #endif | ||
1639 | #endif | ||
1640 | #ifdef MSW | ||
1641 | if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup"); | ||
1642 | #endif | ||
1643 | |||
1644 | if (sys_nogui) | ||
1645 | { | ||
1646 | /* fake the GUI's message giving cwd and font sizes; then | ||
1647 | skip starting the GUI up. */ | ||
1648 | t_atom zz[19]; | ||
1649 | int i; | ||
1650 | #ifdef MSW | ||
1651 | if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0) | ||
1652 | strcpy(cmdbuf, "."); | ||
1653 | #endif | ||
1654 | #ifdef UNIX | ||
1655 | if (!getcwd(cmdbuf, MAXPDSTRING)) | ||
1656 | strcpy(cmdbuf, "."); | ||
1657 | |||
1658 | #endif | ||
1659 | SETSYMBOL(zz, gensym(cmdbuf)); | ||
1660 | for (i = 1; i < 22; i++) | ||
1661 | SETFLOAT(zz + i, defaultfontshit[i-1]); | ||
1662 | SETFLOAT(zz+22,0); | ||
1663 | glob_initfromgui(0, 0, 23, zz); | ||
1664 | } | ||
1665 | else | ||
1666 | { | ||
1667 | #ifdef MSW | ||
1668 | char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80]; | ||
1669 | int spawnret; | ||
1670 | |||
1671 | #endif | ||
1672 | #ifdef MSW | ||
1673 | char intarg; | ||
1674 | #else | ||
1675 | int intarg; | ||
1676 | #endif | ||
1677 | |||
1678 | /* create a socket */ | ||
1679 | xsock = socket(AF_INET, SOCK_STREAM, 0); | ||
1680 | if (xsock < 0) sys_sockerror("socket"); | ||
1681 | #if 0 | ||
1682 | intarg = 0; | ||
1683 | if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF, | ||
1684 | &intarg, sizeof(intarg)) < 0) | ||
1685 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
1686 | intarg = 0; | ||
1687 | if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF, | ||
1688 | &intarg, sizeof(intarg)) < 0) | ||
1689 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
1690 | #endif | ||
1691 | intarg = 1; | ||
1692 | if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY, | ||
1693 | &intarg, sizeof(intarg)) < 0) | ||
1694 | #ifndef MSW | ||
1695 | post("setsockopt (TCP_NODELAY) failed\n") | ||
1696 | #endif | ||
1697 | ; | ||
1698 | |||
1699 | |||
1700 | server.sin_family = AF_INET; | ||
1701 | server.sin_addr.s_addr = INADDR_ANY; | ||
1702 | |||
1703 | /* assign server port number */ | ||
1704 | server.sin_port = htons((unsigned short)portno); | ||
1705 | |||
1706 | /* name the socket */ | ||
1707 | while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0) | ||
1708 | { | ||
1709 | #ifdef MSW | ||
1710 | int err = WSAGetLastError(); | ||
1711 | #endif | ||
1712 | #ifdef UNIX | ||
1713 | int err = errno; | ||
1714 | #endif | ||
1715 | if ((ntry++ > 20) || (err != EADDRINUSE)) | ||
1716 | { | ||
1717 | perror("bind"); | ||
1718 | fprintf(stderr, | ||
1719 | "Pd needs your machine to be configured with\n"); | ||
1720 | fprintf(stderr, | ||
1721 | "'networking' turned on (see Pd's html doc for details.)\n"); | ||
1722 | exit(1); | ||
1723 | } | ||
1724 | portno++; | ||
1725 | server.sin_port = htons((unsigned short)(portno)); | ||
1726 | } | ||
1727 | |||
1728 | if (sys_verbose) fprintf(stderr, "port %d\n", portno); | ||
1729 | |||
1730 | sys_socketreceiver = socketreceiver_new(0, 0, 0, 0); | ||
1731 | |||
1732 | #ifdef UNIX | ||
1733 | childpid = fork(); | ||
1734 | if (childpid < 0) | ||
1735 | { | ||
1736 | if (errno) perror("sys_startgui"); | ||
1737 | else fprintf(stderr, "sys_startgui failed\n"); | ||
1738 | return (1); | ||
1739 | } | ||
1740 | else if (!childpid) /* we're the child */ | ||
1741 | { | ||
1742 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1743 | #ifndef MACOSX | ||
1744 | /* the wish process in Unix will make a wish shell and | ||
1745 | read/write standard in and out unless we close the | ||
1746 | file descriptors. Somehow this doesn't make the MAC OSX | ||
1747 | version of Wish happy...*/ | ||
1748 | if (pipe(stdinpipe) < 0) | ||
1749 | sys_sockerror("pipe"); | ||
1750 | else | ||
1751 | { | ||
1752 | if (stdinpipe[0] != 0) | ||
1753 | { | ||
1754 | close (0); | ||
1755 | dup2(stdinpipe[0], 0); | ||
1756 | close(stdinpipe[0]); | ||
1757 | } | ||
1758 | } | ||
1759 | #endif | ||
1760 | if (!sys_guicmd) | ||
1761 | { | ||
1762 | #ifdef MACOSX | ||
1763 | char *homedir = getenv("HOME"), filename[250]; | ||
1764 | struct stat statbuf; | ||
1765 | if (!homedir || strlen(homedir) > 150) | ||
1766 | goto nohomedir; | ||
1767 | sprintf(filename, | ||
1768 | "%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell", | ||
1769 | homedir); | ||
1770 | if (stat(filename, &statbuf) >= 0) | ||
1771 | goto foundit; | ||
1772 | sprintf(filename, | ||
1773 | "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell", | ||
1774 | homedir); | ||
1775 | if (stat(filename, &statbuf) >= 0) | ||
1776 | goto foundit; | ||
1777 | nohomedir: | ||
1778 | strcpy(filename, | ||
1779 | "/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell"); | ||
1780 | if (stat(filename, &statbuf) >= 0) | ||
1781 | goto foundit; | ||
1782 | strcpy(filename, | ||
1783 | "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell"); | ||
1784 | foundit: | ||
1785 | sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno); | ||
1786 | #else | ||
1787 | sprintf(cmdbuf, | ||
1788 | "TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \ | ||
1789 | \"%s/pd-gui\" %d\n", | ||
1790 | sys_libdir->s_name, sys_libdir->s_name, guidir, portno); | ||
1791 | #endif | ||
1792 | sys_guicmd = cmdbuf; | ||
1793 | } | ||
1794 | if (sys_verbose) fprintf(stderr, "%s", sys_guicmd); | ||
1795 | execl("/bin/sh", "sh", "-c", sys_guicmd, 0); | ||
1796 | perror("pd: exec"); | ||
1797 | _exit(1); | ||
1798 | } | ||
1799 | #endif /* UNIX */ | ||
1800 | |||
1801 | #ifdef MSW | ||
1802 | /* in MSW land "guipath" is unused; we just do everything from | ||
1803 | the libdir. */ | ||
1804 | /* fprintf(stderr, "%s\n", sys_libdir->s_name); */ | ||
1805 | |||
1806 | strcpy(scriptbuf, "\""); | ||
1807 | strcat(scriptbuf, sys_libdir->s_name); | ||
1808 | strcat(scriptbuf, "/" PDBINDIR "pd.tk\""); | ||
1809 | sys_bashfilename(scriptbuf, scriptbuf); | ||
1810 | |||
1811 | sprintf(portbuf, "%d", portno); | ||
1812 | |||
1813 | strcpy(wishbuf, sys_libdir->s_name); | ||
1814 | strcat(wishbuf, "/" PDBINDIR WISHAPP); | ||
1815 | sys_bashfilename(wishbuf, wishbuf); | ||
1816 | |||
1817 | spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0); | ||
1818 | if (spawnret < 0) | ||
1819 | { | ||
1820 | perror("spawnl"); | ||
1821 | fprintf(stderr, "%s: couldn't load TCL\n", wishbuf); | ||
1822 | exit(1); | ||
1823 | } | ||
1824 | |||
1825 | #endif /* MSW */ | ||
1826 | } | ||
1827 | |||
1828 | #ifdef __linux__ | ||
1829 | /* now that we've spun off the child process we can promote | ||
1830 | our process's priority, if we happen to be root. */ | ||
1831 | if (sys_hipriority) | ||
1832 | { | ||
1833 | if (!getuid() || !geteuid()) | ||
1834 | { | ||
1835 | /* To prevent lockup, we fork off a watchdog process with | ||
1836 | higher real-time priority than ours. The GUI has to send | ||
1837 | a stream of ping messages to the watchdog THROUGH the Pd | ||
1838 | process which has to pick them up from the GUI and forward | ||
1839 | them. If any of these things aren't happening the watchdog | ||
1840 | starts sending "stop" and "cont" signals to the Pd process | ||
1841 | to make it timeshare with the rest of the system. (Version | ||
1842 | 0.33P2 : if there's no GUI, the watchdog pinging is done | ||
1843 | from the scheduler idle routine in this process instead.) */ | ||
1844 | |||
1845 | int pipe9[2], watchpid; | ||
1846 | if (pipe(pipe9) < 0) | ||
1847 | { | ||
1848 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1849 | sys_sockerror("pipe"); | ||
1850 | return (1); | ||
1851 | } | ||
1852 | watchpid = fork(); | ||
1853 | if (watchpid < 0) | ||
1854 | { | ||
1855 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1856 | if (errno) | ||
1857 | perror("sys_startgui"); | ||
1858 | else fprintf(stderr, "sys_startgui failed\n"); | ||
1859 | return (1); | ||
1860 | } | ||
1861 | else if (!watchpid) /* we're the child */ | ||
1862 | { | ||
1863 | sys_set_priority(1); | ||
1864 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1865 | if (pipe9[1] != 0) | ||
1866 | { | ||
1867 | dup2(pipe9[0], 0); | ||
1868 | close(pipe9[0]); | ||
1869 | } | ||
1870 | close(pipe9[1]); | ||
1871 | |||
1872 | sprintf(cmdbuf, "%s/pd-watchdog\n", guidir); | ||
1873 | if (sys_verbose) fprintf(stderr, "%s", cmdbuf); | ||
1874 | execl("/bin/sh", "sh", "-c", cmdbuf, 0); | ||
1875 | perror("pd: exec"); | ||
1876 | _exit(1); | ||
1877 | } | ||
1878 | else /* we're the parent */ | ||
1879 | { | ||
1880 | sys_set_priority(0); | ||
1881 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1882 | close(pipe9[0]); | ||
1883 | sys_watchfd = pipe9[1]; | ||
1884 | /* We also have to start the ping loop in the GUI; | ||
1885 | this is done later when the socket is open. */ | ||
1886 | } | ||
1887 | } | ||
1888 | else | ||
1889 | { | ||
1890 | post("realtime setting failed because not root\n"); | ||
1891 | sys_hipriority = 0; | ||
1892 | } | ||
1893 | } | ||
1894 | |||
1895 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1896 | #endif /* __linux__ */ | ||
1897 | |||
1898 | #ifdef MSW | ||
1899 | if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) | ||
1900 | fprintf(stderr, "pd: couldn't set high priority class\n"); | ||
1901 | #endif | ||
1902 | #ifdef MACOSX | ||
1903 | if (sys_hipriority) | ||
1904 | { | ||
1905 | struct sched_param param; | ||
1906 | int policy = SCHED_RR; | ||
1907 | int err; | ||
1908 | param.sched_priority = 80; // adjust 0 : 100 | ||
1909 | |||
1910 | err = pthread_setschedparam(pthread_self(), policy, ¶m); | ||
1911 | if (err) | ||
1912 | post("warning: high priority scheduling failed\n"); | ||
1913 | } | ||
1914 | #endif /* MACOSX */ | ||
1915 | |||
1916 | if (!sys_nogui) | ||
1917 | { | ||
1918 | char buf[256]; | ||
1919 | if (sys_verbose) | ||
1920 | fprintf(stderr, "Waiting for connection request... \n"); | ||
1921 | if (listen(xsock, 5) < 0) sys_sockerror("listen"); | ||
1922 | |||
1923 | sys_guisock = accept(xsock, (struct sockaddr *) &server, &len); | ||
1924 | #ifdef OOPS | ||
1925 | close(xsock); | ||
1926 | #endif | ||
1927 | if (sys_guisock < 0) sys_sockerror("accept"); | ||
1928 | sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read, | ||
1929 | sys_socketreceiver); | ||
1930 | |||
1931 | if (sys_verbose) | ||
1932 | fprintf(stderr, "... connected\n"); | ||
1933 | |||
1934 | /* here is where we start the pinging. */ | ||
1935 | #ifdef __linux__ | ||
1936 | if (sys_hipriority) | ||
1937 | sys_gui("pdtk_watchdog\n"); | ||
1938 | #endif | ||
1939 | sys_get_audio_apis(buf); | ||
1940 | sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf); | ||
1941 | } | ||
1942 | if (sys_stdin) { | ||
1943 | set_keypress(); | ||
1944 | _ss = gensym("stdin"); | ||
1945 | sys_addpollfn(1, (t_fdpollfn) stdin_read,NULL); | ||
1946 | } | ||
1947 | return (0); | ||
1948 | |||
1949 | } | ||
1950 | |||
1951 | |||
1952 | static int sys_poll_togui(void) | ||
1953 | { | ||
1954 | /* LATER use this to flush output buffer to gui */ | ||
1955 | return (0); | ||
1956 | } | ||
1957 | |||
1958 | int sys_pollgui(void) | ||
1959 | { | ||
1960 | return (sys_domicrosleep(0, 1) || sys_poll_togui()); | ||
1961 | } | ||
1962 | |||
1963 | |||
1964 | /* T.Grill - import clean quit function */ | ||
1965 | extern void sys_exit(void); | ||
1966 | |||
1967 | /* This is called when something bad has happened, like a segfault. | ||
1968 | Call glob_quit() below to exit cleanly. | ||
1969 | LATER try to save dirty documents even in the bad case. */ | ||
1970 | void sys_bail(int n) | ||
1971 | { | ||
1972 | static int reentered = 0; | ||
1973 | reset_keypress(); | ||
1974 | if (!reentered) | ||
1975 | { | ||
1976 | reentered = 1; | ||
1977 | #ifndef __linux /* sys_close_audio() hangs if you're in a signal? */ | ||
1978 | fprintf(stderr, "closing audio...\n"); | ||
1979 | sys_close_audio(); | ||
1980 | fprintf(stderr, "closing MIDI...\n"); | ||
1981 | sys_close_midi(); | ||
1982 | fprintf(stderr, "... done.\n"); | ||
1983 | #endif | ||
1984 | exit(1); | ||
1985 | } | ||
1986 | else _exit(n); | ||
1987 | } | ||
1988 | |||
1989 | void glob_quit(void *dummy) | ||
1990 | { | ||
1991 | sys_vgui("exit\n"); | ||
1992 | if (!sys_nogui) | ||
1993 | { | ||
1994 | close(sys_guisock); | ||
1995 | sys_rmpollfn(sys_guisock); | ||
1996 | } | ||
1997 | reset_keypress(); | ||
1998 | sys_bail(0); | ||
1999 | } | ||
2000 | |||