Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

open-axiom repository from github

24005 views
1
/*
2
Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd.
3
All rights reserved.
4
5
Copyright (C) 2007-2013, Gabriel Dos Reis.
6
All rights reserved.
7
8
Redistribution and use in source and binary forms, with or without
9
modification, are permitted provided that the following conditions are
10
met:
11
12
- Redistributions of source code must retain the above copyright
13
notice, this list of conditions and the following disclaimer.
14
15
- Redistributions in binary form must reproduce the above copyright
16
notice, this list of conditions and the following disclaimer in
17
the documentation and/or other materials provided with the
18
distribution.
19
20
- Neither the name of The Numerical ALgorithms Group Ltd. nor the
21
names of its contributors may be used to endorse or promote products
22
derived from this software without specific prior written permission.
23
24
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
*/
36
37
/* #define DEBUG */
38
#define _SESSION_C
39
40
#include <stdlib.h>
41
#include <sys/time.h>
42
#include <stdio.h>
43
#include <string.h>
44
#include <signal.h>
45
#include <locale.h>
46
47
#include "open-axiom.h"
48
#include "sockio.h"
49
#include "com.h"
50
#include "bsdsignal.h"
51
#include "cfuns.h"
52
#include "sockio.h"
53
54
using namespace OpenAxiom;
55
56
static void usr1_handler(int);
57
static void usr2_handler(int);
58
static void term_handler(int);
59
static void close_client(int);
60
static void read_SpadServer_command(void);
61
static int test_sock_for_process(openaxiom_sio*);
62
static void read_menu_client_command(void);
63
static void read_from_spad_io(void);
64
static void kill_spad(void);
65
static int accept_session_connection(openaxiom_sio*);
66
static void read_from_session(openaxiom_sio*);
67
static void manage_sessions(void);
68
69
70
#define BufSize 4096 /* size of communication buffer */
71
72
typedef struct sock_list { /* linked list of Sock */
73
openaxiom_sio Socket;
74
struct sock_list *next;
75
} Sock_List;
76
77
openaxiom_sio* spad_io = 0; /* to_server socket for SessionIO */
78
openaxiom_sio* spad_server = 0; /* to_server socket for SpadServer */
79
openaxiom_sio* menu_client = 0; /* to_client socket for MenuServerName */
80
openaxiom_sio* active_session = 0; /* pointer to currently active session */
81
82
Sock_List *plSock = (Sock_List *) 0;
83
84
char big_bad_buf[BufSize]; /* big I/O buffer */
85
int num_active_clients = 0; /* number of InterpWindows attached */
86
int reading_output = 0;
87
fd_set session_socket_mask;
88
89
static void
90
usr1_handler(int sig)
91
{
92
return;
93
}
94
95
static void
96
usr2_handler(int sig)
97
{
98
send_signal(spad_server, SIGINT);
99
return;
100
}
101
102
static void
103
term_handler(int sig)
104
{
105
exit(1);
106
}
107
108
static void
109
pr()
110
{
111
Sock_List *pSock;
112
113
fprintf(stderr,"The socket list:\n");
114
for(pSock=plSock;pSock!=(Sock_List *)0;pSock=pSock->next){
115
fprintf(stderr,"(%d,%d,%d)\t",pSock->Socket.pid,2<<(pSock->Socket.socket),pSock->Socket.frame);
116
}
117
fprintf(stderr,"\n");
118
}
119
120
static void
121
close_client(int frame)
122
{
123
Sock_List *pSock,*locSock;
124
int socket_fd;
125
126
/* we will check for frame equality,
127
kill with send_signal,
128
notify HyperTex so that it updates its list (if it's a spadbuf),
129
repair the list,
130
unset the active_session,
131
update num_active_clients
132
*/
133
134
135
/* first check head */
136
#ifdef DEBUG
137
fprintf(stderr,"close_client(%d)\n",frame);
138
#endif
139
140
if ( (plSock) && (plSock->Socket.frame == frame) ){
141
socket_fd = plSock->Socket.socket;
142
send_signal((openaxiom_sio *)plSock, SIGTERM);
143
if ( menu_client != (openaxiom_sio *) 0){
144
send_int(menu_client,CloseClient);
145
send_int(menu_client,(*plSock).Socket.pid);
146
}
147
#ifdef DEBUG
148
fprintf(stderr,"trying to clear %u\n",socket_fd);
149
#endif
150
FD_CLR(socket_fd,&session_socket_mask);
151
locSock = plSock;
152
if ((*plSock).next == (Sock_List *) 0)
153
{plSock = (Sock_List *) 0;}
154
else
155
{plSock = plSock->next;}
156
active_session = (openaxiom_sio *) 0;
157
num_active_clients--;
158
free(locSock);
159
}
160
161
/* now check the rest */
162
163
else {
164
for (pSock=plSock; pSock->next != (Sock_List *) 0 ; pSock=pSock->next)
165
if (pSock->next->Socket.frame == frame){
166
socket_fd = pSock->next->Socket.socket;
167
send_signal((openaxiom_sio *)pSock->next, SIGTERM);
168
if ( menu_client != (openaxiom_sio *) 0){
169
send_int(menu_client,CloseClient);
170
send_int(menu_client,(*plSock).Socket.pid);
171
}
172
#ifdef DEBUG
173
fprintf(stderr,"trying to clear %u\n",socket_fd);
174
#endif
175
FD_CLR(socket_fd,&session_socket_mask);
176
locSock = pSock->next;
177
if ( pSock->next->next == (Sock_List *) 0 )
178
{ pSock->next= (Sock_List *) 0;}
179
else
180
{ pSock->next = pSock->next->next;}
181
num_active_clients--;
182
active_session = (openaxiom_sio *) 0;
183
free(locSock);
184
break;
185
}
186
}
187
#ifdef DEBUG
188
pr();
189
#endif
190
}
191
192
static void
193
read_SpadServer_command(void)
194
{
195
int cmd, frame, num;
196
cmd = get_int(spad_server);
197
switch (cmd) {
198
case EndOfOutput:
199
if (menu_client != (openaxiom_sio *) 0) send_signal(menu_client, SIGUSR2);
200
if (reading_output != 0) reading_output = 0;
201
break;
202
case QueryClients:
203
/* don't count MenuServer */
204
num = num_active_clients ;
205
send_int(spad_server, num);
206
break;
207
case CloseClient:
208
frame = get_int(spad_server);
209
if (frame != -1) close_client(frame);
210
break;
211
case SendXEventToHyperTeX:
212
break;
213
default:
214
fprintf(stderr, "session : unknown command from SpadServer %d\n", cmd);
215
break;
216
}
217
}
218
219
static int
220
test_sock_for_process(openaxiom_sio *sock)
221
{
222
if (sock == (openaxiom_sio *)0 ) return -1;
223
return kill(sock->pid, 0);
224
}
225
226
static void
227
read_menu_client_command(void)
228
{
229
int cmd,frame, i,socket_fd;
230
Sock_List *pSock;
231
232
/* save it for possible clearing */
233
socket_fd = menu_client->socket;
234
235
if (test_sock_for_process(menu_client) == -1) {
236
FD_CLR(socket_fd,&session_socket_mask);
237
menu_client = (openaxiom_sio *) 0;
238
reading_output = 0;
239
return;
240
}
241
cmd = get_int(menu_client);
242
switch(cmd) {
243
case -1: /* socket closed */
244
FD_CLR(socket_fd,&session_socket_mask);
245
menu_client = (openaxiom_sio *) 0;
246
reading_output = 0;
247
break;
248
case SwitchFrames:
249
#ifdef DEBUG
250
fprintf(stderr,"menu:SwitchFrames\n");
251
#endif
252
frame = get_int(menu_client);
253
send_int(spad_server, SwitchFrames);
254
send_int(spad_server, frame);
255
for(i=0,pSock=plSock; pSock != (Sock_List *) 0 ; i++,pSock=pSock->next)
256
if (pSock->Socket.frame == frame) {
257
active_session = (openaxiom_sio *)pSock;
258
reading_output = 1;
259
break;
260
}
261
if (i == num_active_clients) {
262
/* fprintf(stderr, "Couldn't find socket for frame %d\n", frame); */
263
}
264
break;
265
case QuerySpad:
266
#ifdef DEBUG
267
fprintf(stderr,"menu:QuerySpad\n");
268
#endif
269
send_int(menu_client, reading_output);
270
break;
271
default:
272
fprintf(stderr, "session : unknown command from MenuServer: %d\n", cmd);
273
menu_client = (openaxiom_sio *) 0;
274
break;
275
}
276
}
277
278
static void
279
read_from_spad_io(void)
280
{
281
int ret_code;
282
ret_code = sread(spad_io, byte_address(big_bad_buf), BufSize,
283
"session: stdout socket");
284
if (ret_code == -1) return;
285
if(active_session != (openaxiom_sio *) 0) {
286
ret_code = swrite(active_session, byte_address(big_bad_buf),
287
ret_code, NULL);
288
}
289
}
290
291
static void
292
kill_spad(void)
293
{
294
int i;
295
Sock_List *pSock;
296
297
send_signal(spad_server, SIGTERM);
298
for (pSock=plSock,i=0;
299
(i<num_active_clients) && (pSock != (Sock_List *) 0);
300
i++,pSock=pSock->next) {
301
if ((pSock->Socket).socket != 0)
302
send_signal((openaxiom_sio *)pSock, SIGTERM);
303
}
304
if (menu_client != (openaxiom_sio *) 0) send_signal(menu_client, SIGTERM);
305
exit(0);
306
}
307
308
static int
309
accept_session_connection(openaxiom_sio *server_sock)
310
{
311
int sock_fd, ret_code;
312
Sock_List *pls;
313
314
/* Could be three things : KillSpad MenuServer InterpWindow */
315
316
pls = (Sock_List *) malloc(sizeof (Sock_List));
317
sock_fd = accept(server_sock->socket, 0, 0);
318
if (sock_fd == -1) {
319
perror("session : accepting connection");
320
return -1;
321
}
322
(pls->Socket).socket = sock_fd;
323
get_socket_type((openaxiom_sio *)pls);
324
325
switch((pls->Socket).purpose) {
326
case KillSpad:
327
kill_spad();
328
return KillSpad;
329
free(pls);
330
case MenuServer:
331
#ifdef DEBUG
332
fprintf(stderr,"session: accepted MenuServer , fd = %d\n",sock_fd);
333
#endif
334
menu_client = &(pls->Socket);
335
FD_SET(menu_client->socket, &session_socket_mask);
336
return MenuServer;
337
case InterpWindow:
338
#ifdef DEBUG
339
fprintf(stderr,"session: accepted InterpWindow , fd = %d\n",sock_fd);
340
#endif
341
342
/* new Sock is put at the head of the list */
343
if (plSock == (Sock_List *)0 ) {
344
plSock = pls;
345
plSock->next = (Sock_List *)0 ;
346
}
347
else{
348
pls->next = plSock;
349
plSock = pls;
350
}
351
352
/* we need to maintain session_socket_mask here since we roll our own accept */
353
354
FD_SET(plSock->Socket.socket, &session_socket_mask);
355
send_int(spad_server, CreateFrame);
356
plSock->Socket.frame = get_int(spad_server);
357
active_session = (openaxiom_sio *)plSock;
358
get_string_buf(spad_server, big_bad_buf, BufSize);
359
ret_code = swrite((openaxiom_sio *)plSock,
360
byte_address(big_bad_buf),
361
strlen(big_bad_buf)+1,
362
"session: writing to InterpWindow");
363
if (ret_code == -1)
364
return -1;
365
num_active_clients++;
366
#ifdef DEBUG
367
pr();
368
#endif
369
return plSock->Socket.purpose;
370
}
371
return (-1);
372
}
373
374
static void
375
read_from_session(openaxiom_sio *sock)
376
{
377
int ret_code;
378
if (sock != active_session) {
379
send_int(spad_server, SwitchFrames);
380
send_int(spad_server, sock->frame);
381
}
382
active_session = sock;
383
ret_code = sread(sock, byte_address(big_bad_buf), BufSize,
384
"session: reading InterpWindow");
385
if (ret_code == -1) {
386
active_session = (openaxiom_sio *) 0;
387
reading_output = 0;
388
return;
389
}
390
ret_code = swrite(spad_io, byte_address(big_bad_buf), ret_code,
391
"session: writing SessionIO");
392
if (ret_code == -1) {
393
active_session = (openaxiom_sio *)0 ;
394
reading_output = 0;
395
return;
396
}
397
reading_output = 1;
398
}
399
400
static void
401
manage_sessions(void)
402
{
403
int ret_code;
404
fd_set rd, wr, ex;
405
Sock_List *pSock;
406
407
reading_output = 0;
408
while (1) {
409
FD_ZERO(&rd);
410
FD_ZERO(&wr);
411
FD_ZERO(&ex);
412
413
/* Allow server socket and all connections if not waiting for output
414
socket_mask is maintained by libspad.a */
415
#ifdef DEBUG
416
fprintf(stderr,"session_socket_mask=%u ",*((long *)session_socket_mask.fds_bits));
417
#endif
418
rd = session_socket_mask;
419
if (!reading_output) {
420
rd = session_socket_mask;
421
}
422
423
/* Allow the active_session if set */
424
if (active_session) FD_SET(active_session->socket, &rd);
425
#ifdef DEBUG
426
fprintf(stderr,"[rd=%u ",*((long *)rd.fds_bits));
427
#endif
428
429
ret_code = sselect(FD_SETSIZE, &rd, &wr, &ex, NULL);
430
if (ret_code == -1) {
431
break;
432
}
433
#ifdef DEBUG
434
fprintf(stderr,"rd=%u]\n",*((long *)rd.fds_bits));
435
#endif
436
437
if ((menu_client != (openaxiom_sio *) 0)
438
&& FD_ISSET(menu_client->socket, &rd)) {
439
/* MenuServer wants to talk */
440
read_menu_client_command(); }
441
442
443
if (FD_ISSET(spad_io->socket, &rd)) {
444
/* Lisp has output */
445
read_from_spad_io(); }
446
447
448
if (FD_ISSET(server.socket, &rd)) {
449
/* Someone wants to connect to our server socket */
450
accept_session_connection(&server); }
451
452
453
for(pSock=plSock; pSock != (Sock_List *) 0 ; pSock=pSock->next) {
454
if ((active_session == (openaxiom_sio *)pSock || !reading_output) &&
455
(pSock->Socket).socket>0 && FD_ISSET(pSock->Socket.socket, &rd)) {
456
/* An InterpWindow */
457
read_from_session((openaxiom_sio *)pSock); }
458
}
459
460
461
if (FD_ISSET(spad_server->socket, &rd)) {
462
/* The Lisp socket */
463
read_SpadServer_command(); }
464
}
465
}
466
467
int
468
main(void)
469
{
470
using namespace OpenAxiom;
471
#ifdef DEBUG2
472
/* delay for attaching with debugger before interesting things happen */
473
openaxiom_sleep(30);
474
#endif
475
476
oa_setenv("LC_ALL", "C");
477
setlocale(LC_ALL, "");
478
/* spad_server connects to Lisp server socket
479
read_SpadServer_command handles requests */
480
spad_server = connect_to_local_server(SpadServer, SessionManager, Forever);
481
if (spad_server == (openaxiom_sio *) 0) {
482
fprintf(stderr, "session: Cannot connect to OpenAxiom server!\n");
483
exit(0);
484
}
485
else {
486
#ifdef DEBUG
487
fprintf(stderr, "session: connected SpadServer , fd = %d\n",
488
spad_server->socket);
489
#endif
490
FD_SET(spad_server->socket, &session_socket_mask);
491
}
492
493
494
/* spad_io connects to SessionIOName server socket
495
this is Lisp std IO read_from_spad_io handles requests */
496
spad_io = connect_to_local_server(SessionIOName, SessionIO, Forever);
497
if (spad_io == (openaxiom_sio *) 0) {
498
fprintf(stderr, "session: Cannot connect to OpenAxiom IO!\n");
499
exit(0);
500
}
501
else {
502
#ifdef DEBUG
503
fprintf(stderr,"session: connected SessionIOName , fd = %d\n",
504
spad_io->socket);
505
#endif
506
FD_SET(spad_io->socket, &session_socket_mask);
507
}
508
bsdSignal(SIGUSR2, usr2_handler,DontRestartSystemCalls);
509
bsdSignal(SIGUSR1, usr1_handler,RestartSystemCalls);
510
bsdSignal(SIGINT, SIG_IGN,RestartSystemCalls);
511
bsdSignal(SIGTERM, term_handler,RestartSystemCalls);
512
513
/* open_server opens the server socket so that we can accept connections
514
we expect connections from spadbuf/spadclient(purpose:InterpWindow)
515
and hypertex (MenuServer) */
516
517
if (open_server(SessionServer) == -2) {
518
fprintf(stderr, "session: Cannot make server socket!\n");
519
exit(-1);
520
}
521
else {
522
#ifdef DEBUG
523
fprintf(stderr, "session: opened SessionServer , fd = %d\n",
524
server.socket);
525
#endif
526
FD_SET(server.socket,&session_socket_mask);
527
}
528
manage_sessions();
529
return(0);
530
}
531
532
533
534