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
Copyright (C) 2007-2013, Gabriel Dos Reis.
5
All rights reserved.
6
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions are
9
met:
10
11
- Redistributions of source code must retain the above copyright
12
notice, this list of conditions and the following disclaimer.
13
14
- Redistributions in binary form must reproduce the above copyright
15
notice, this list of conditions and the following disclaimer in
16
the documentation and/or other materials provided with the
17
distribution.
18
19
- Neither the name of The Numerical ALgorithms Group Ltd. nor the
20
names of its contributors may be used to endorse or promote products
21
derived from this software without specific prior written permission.
22
23
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
27
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
*/
35
36
/* socket i/o primitives */
37
38
#include <stdio.h>
39
#include <stdlib.h>
40
41
#include <errno.h>
42
#include <sys/types.h>
43
#include <sys/stat.h>
44
#include <unistd.h>
45
46
#include <sys/time.h>
47
#include <string.h>
48
#include <signal.h>
49
#ifdef __WIN32__
50
# include <winsock2.h>
51
# include <ws2tcpip.h>
52
#else
53
# include <arpa/inet.h>
54
# include <netdb.h>
55
#endif
56
57
#include "cfuns.h"
58
#include "sockio.h"
59
#include "com.h"
60
#include "bsdsignal.h"
61
#include "sockio.h"
62
63
namespace OpenAxiom {
64
65
#define TotalMaxPurposes 50
66
#define MaxServerNumbers 100
67
#define accept_if_needed(purpose) \
68
( purpose_table[purpose] == NULL ? sock_accept_connection(purpose) : 1 )
69
70
/* Note that the name AF_LOCAL is more portable than AF_UNIX, but MingW
71
implementation and Windows documentation don't always agree. */
72
73
#if HAVE_AF_LOCAL
74
# define OPENAXIOM_AF_LOCAL AF_LOCAL
75
#elif HAVE_AF_UNIX
76
# define OPENAXIOM_AF_LOCAL AF_UNIX
77
#else
78
# error "needs one of AF_LOCAL or AF_UNIX"
79
#endif
80
81
82
/* socket description of spad clients */
83
openaxiom_sio clients[MaxClients];
84
85
/* Local socket for server */
86
openaxiom_sio server;
87
88
/* table of dedicated socket types */
89
openaxiom_sio *purpose_table[TotalMaxPurposes];
90
91
/* bit mask of active sockets */
92
fd_set socket_mask;
93
94
/* bit mask of server sockets */
95
fd_set server_mask;
96
97
/* used to identify closed socket on SIGPIPE */
98
int socket_closed;
99
100
/* spad server number used in sman */
101
int spad_server_number = -1;
102
103
104
/* Non zero if the host system module support for socket is activated.
105
This is needed only for MS platforms. */
106
static int openaxiom_socket_module_loaded = 0;
107
108
#ifdef __WIN32__
109
/* Windows require some handshaking with the WinSock DLL before
110
we can even think about talking about sockets. */
111
112
static void
113
openaxiom_unload_socket_module()
114
{
115
WSACleanup();
116
openaxiom_socket_module_loaded = 0;
117
}
118
#endif
119
120
121
static void
122
openaxiom_load_socket_module()
123
{
124
if (!openaxiom_socket_module_loaded) {
125
#ifdef __WIN32__
126
WSADATA wsaData;
127
128
/* Request version 2.0 of WinSock DLL. */
129
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
130
perror("could not find suitable WinSock DLL.");
131
exit(WSAGetLastError());
132
}
133
134
atexit(&openaxiom_unload_socket_module);
135
136
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) {
137
perror("could not find suitable WinSock DLL.");
138
exit(WSAGetLastError());
139
}
140
#endif
141
}
142
openaxiom_socket_module_loaded = 1;
143
}
144
145
146
/* Convert an IP address from presentation (string or ascii form)
147
to numeric form. The result is stored in the last argument.
148
Success is indicated by a return value 0; failure is -1. */
149
OPENAXIOM_C_EXPORT int
150
oa_inet_pton(const char* addr, int prot, Byte* bytes)
151
{
152
openaxiom_load_socket_module();
153
switch (prot) {
154
case 4: {
155
#ifdef __WIN32__
156
unsigned long inet_val = inet_addr(addr);
157
if (inet_val == INADDR_NONE || inet_val == INADDR_ANY)
158
return -1;
159
memcpy(bytes, &inet_val, 4);
160
return 0;
161
#else
162
struct in_addr inet_val;
163
if (inet_aton(addr, &inet_val) != 0) {
164
memcpy(bytes, &inet_val, 4);
165
return 0;
166
}
167
return -1;
168
#endif
169
}
170
default:
171
return -1;
172
}
173
}
174
175
/* Resolve a hostname to its IP address. On success return 0,
176
otherwise -1. */
177
OPENAXIOM_C_EXPORT int
178
oa_get_host_address(const char* n, int prot, Byte* bytes)
179
{
180
struct hostent* h;
181
openaxiom_load_socket_module();
182
h = gethostbyname(n);
183
if (h == 0)
184
return -1;
185
186
if (h->h_length != prot)
187
/* Protocol mismatch. */
188
return -1;
189
memcpy(bytes, h->h_addr_list[0], prot);
190
return 0;
191
}
192
193
194
/* Get a socket identifier to a local server. We take whatever protocol
195
is the default for the address family in the SOCK_STREAM type. */
196
static inline openaxiom_socket
197
openaxiom_socket_stream_link(int family)
198
{
199
openaxiom_load_socket_module();
200
return socket(family, SOCK_STREAM, 0);
201
}
202
203
204
/* Returns 1 if SOCKET is an invalid socket. Otherwise return 0. */
205
206
static inline int
207
openaxiom_socket_is_invalid(openaxiom_socket sock)
208
{
209
#ifdef __WIN32__
210
return sock == INVALID_SOCKET;
211
#else
212
return sock < 0;
213
#endif
214
}
215
216
static inline int
217
is_invalid_socket(const openaxiom_sio* s)
218
{
219
return openaxiom_socket_is_invalid(s->socket);
220
}
221
222
/* Returns 1 if SOCKET is a valid socket. Otherwise return 0. */
223
224
static inline int
225
is_valid_socket(const openaxiom_sio* s)
226
{
227
#ifdef __WIN32__
228
return s->socket != INVALID_SOCKET;
229
#else
230
return s->socket > 0;
231
#endif
232
}
233
234
235
/* Because a socket on Windows platform is a not just a simple file
236
descriptor as it is in the Unix world, it is invalid to use
237
a socket identifier as argument for read(), or close, or
238
any other file descriptor function. Furthermore, Windows
239
requires cleanup. */
240
241
OPENAXIOM_C_EXPORT void
242
oa_close_socket(openaxiom_socket s)
243
{
244
#ifdef __WIN32__
245
shutdown(s, SD_BOTH);
246
closesocket(s);
247
#else
248
close(s);
249
#endif
250
}
251
252
/* Local IPC Socket:
253
On POSIX systems, this is just the Local IPC Socket.
254
On Windows, we Windows Named Pipes.
255
256
Please, remember that Windows Named Pipes are closer to
257
Unix Domain Sockets than they are to Unix Named Pipes. They
258
ae full duplex communication links, supporting regular
259
file I/O operations. */
260
261
OPENAXIOM_C_EXPORT openaxiom_filedesc
262
oa_open_local_client_stream_socket(const char* path)
263
{
264
#ifdef __WIN32__
265
# define NAMED_PIPE_PREFIX "\\\\.\\pipe"
266
char* pipename;
267
HANDLE handle;
268
269
pipename = (char *) malloc(sizeof NAMED_PIPE_PREFIX + strlen(path));
270
strcpy(pipename, NAMED_PIPE_PREFIX);
271
strcat(pipename, path);
272
273
/* Try to open only an existing named pipe. */
274
while (1) {
275
handle = CreateFile(/* lpFileName */ pipename,
276
/* dwDesiredAccess */ GENERIC_READ | GENERIC_WRITE,
277
/* dwSharedMode */ 0,
278
/* lpSecurityAttributes */ NULL,
279
/* dwCreationDisposition */ OPEN_EXISTING,
280
/* dwFlagsAttributes */ 0,
281
/* hTemplateFile */ NULL);
282
283
if (handle != INVALID_HANDLE_VALUE)
284
return handle;
285
286
if (GetLastError() != ERROR_PIPE_BUSY
287
|| !WaitNamedPipe(pipename, NMPWAIT_WAIT_FOREVER))
288
return INVALID_HANDLE_VALUE;
289
}
290
# undef NAMED_PIPE_PREFIX
291
#else
292
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
293
struct sockaddr_un addr;
294
if (sock < 0)
295
return -1;
296
297
memset(&addr, 0, sizeof addr);
298
addr.sun_family = OPENAXIOM_AF_LOCAL;
299
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
300
if (connect(sock, (struct sockaddr*)&addr, sizeof addr) < 0) {
301
close(sock);
302
return -1;
303
}
304
return sock;
305
#endif
306
}
307
308
OPENAXIOM_C_EXPORT int
309
oa_filedesc_read(openaxiom_filedesc desc, Byte* buf, int size)
310
{
311
#ifdef __WIN32__
312
DWORD count = -1;
313
if (ReadFile(/* hFile */ desc,
314
/* lpBuffer */ buf,
315
/* nNumberOfBytesToRead */ size,
316
/* lpNumberOfBytesRead */ &count,
317
/* lpOverlapped */ NULL))
318
return count;
319
return -1;
320
#else
321
return read(desc, buf, size);
322
#endif
323
}
324
325
OPENAXIOM_C_EXPORT int
326
oa_filedesc_write(openaxiom_filedesc desc, const Byte* buf, int size)
327
{
328
#ifdef __WIN32__
329
DWORD count = -1;
330
if (WriteFile(/* hFile */ desc,
331
/* lpBuffer */ buf,
332
/* nNumberOfBytesToWrite */ size,
333
/* lpNumberOfBytesWritten */ &count,
334
/* lpOverlapped */ NULL))
335
return count;
336
return -1;
337
#else
338
return write(desc, buf, size);
339
#endif
340
}
341
342
OPENAXIOM_C_EXPORT int
343
oa_filedesc_close(openaxiom_filedesc desc)
344
{
345
#ifdef __WIN32__
346
return CloseHandle(desc) ? 0 : -1;
347
#else
348
return close(desc);
349
#endif
350
}
351
352
/* IP sockets.
353
*/
354
355
OPENAXIOM_C_EXPORT openaxiom_socket
356
oa_connect_ip_port_stream(const Byte* addr, int prot, openaxiom_port port)
357
{
358
struct sockaddr_in server;
359
openaxiom_socket sock;
360
/* IP6 is not yet supported. */
361
if (prot != 4)
362
return OPENAXIOM_INVALID_SOCKET;
363
364
sock = openaxiom_socket_stream_link(AF_INET);
365
if (openaxiom_socket_is_invalid(sock))
366
return OPENAXIOM_INVALID_SOCKET;
367
368
memset(&server, 0, sizeof server);
369
server.sin_family = AF_INET;
370
memcpy(&server.sin_addr, addr, prot);
371
server.sin_port = htons(port);
372
if (connect(sock, (struct sockaddr*)&server, sizeof server) < 0) {
373
oa_close_socket(sock);
374
return OPENAXIOM_INVALID_SOCKET;
375
}
376
return sock;
377
}
378
379
/* It is idiomatic in the Unix/POSIX world to use the standard
380
read() and write() functions on sockets. However, in the Windows
381
world, that is invalid. Consequently, portability suggests that
382
we restrict ourselves to the POSIX standard functions recv() and
383
send(). */
384
385
386
/* Read some bytes of data into buffer `buf' with capacity `size'.
387
On failure, return -1; otherwise return the number of bytes
388
actually read. */
389
390
OPENAXIOM_C_EXPORT int
391
oa_socket_read(openaxiom_socket sock, Byte* buf, int size)
392
{
393
return recv(sock, (char*) buf, size, 0);
394
}
395
396
/* Attempt to read a byte from scoket `sock'.
397
On failure, return -1; otherwise the actual byte read. */
398
399
OPENAXIOM_C_EXPORT int
400
oa_socket_read_byte(openaxiom_socket sock)
401
{
402
Byte byte;
403
if(oa_socket_read(sock, &byte, 1) < 1)
404
return -1;
405
return byte;
406
}
407
408
409
/* Send `size' bytes of data contained in `buf' to the socket `sock'.
410
Return -1 on failured; the number of actualy write bytes on success. */
411
412
OPENAXIOM_C_EXPORT int
413
oa_socket_write(openaxiom_socket sock, const Byte* buf, int size)
414
{
415
return send(sock, (const char*) buf, size, 0);
416
}
417
418
/* Send one byte to socket `sock'. */
419
OPENAXIOM_C_EXPORT int
420
oa_socket_write_byte(openaxiom_socket sock, Byte byte)
421
{
422
return oa_socket_write(sock, &byte, 1) < 1 ? -1 : byte;
423
}
424
425
426
/* Return 1 is the last call was cancelled. */
427
428
static inline int
429
openaxiom_syscall_was_cancelled()
430
{
431
#ifdef __WIN32__
432
return WSAGetLastError() == WSAEINTR;
433
#else
434
return errno == EINTR;
435
#endif
436
}
437
438
/* Return 1 is last connect() was refused. */
439
440
static inline int
441
openaxiom_connection_refused()
442
{
443
#ifdef __WIN32__
444
return WSAGetLastError() == WSAECONNREFUSED;
445
#else
446
return errno == ECONNREFUSED;
447
#endif
448
}
449
450
451
OPENAXIOM_C_EXPORT void
452
sigpipe_handler(int sig)
453
{
454
socket_closed = 1;
455
}
456
457
OPENAXIOM_C_EXPORT int
458
wait_for_client_read(openaxiom_sio *sock, Byte* buf, int buf_size,
459
const char* msg)
460
{
461
int ret_val;
462
switch(sock->purpose) {
463
case SessionManager:
464
case ViewportServer:
465
sock_accept_connection(sock->purpose);
466
ret_val = sread(purpose_table[sock->purpose], buf, buf_size, msg);
467
sock->socket = 0;
468
return ret_val;
469
default:
470
sock->socket = 0;
471
return -1;
472
}
473
}
474
475
OPENAXIOM_C_EXPORT int
476
wait_for_client_write(openaxiom_sio* sock, const Byte* buf,
477
int buf_size, const char* msg)
478
{
479
int ret_val;
480
switch(sock->purpose) {
481
case SessionManager:
482
case ViewportServer:
483
sock_accept_connection(sock->purpose);
484
ret_val = swrite(purpose_table[sock->purpose], buf, buf_size, msg);
485
sock->socket = 0;
486
return ret_val;
487
default:
488
sock->socket = 0;
489
return -1;
490
}
491
}
492
493
OPENAXIOM_C_EXPORT int
494
sread(openaxiom_sio* sock, Byte* buf, int buf_size, const char *msg)
495
{
496
int ret_val;
497
char err_msg[256];
498
errno = 0;
499
do {
500
ret_val = oa_socket_read(sock->socket, buf, buf_size);
501
} while (ret_val == -1 && openaxiom_syscall_was_cancelled());
502
if (ret_val == 0) {
503
FD_CLR(sock->socket, &socket_mask);
504
purpose_table[sock->purpose] = NULL;
505
oa_close_socket(sock->socket);
506
return wait_for_client_read(sock, buf, buf_size, msg);
507
}
508
if (ret_val == -1) {
509
if (msg) {
510
sprintf(err_msg, "reading: %s", msg);
511
perror(err_msg);
512
}
513
return -1;
514
}
515
return ret_val;
516
}
517
518
OPENAXIOM_C_EXPORT int
519
swrite(openaxiom_sio* sock, const Byte* buf, int buf_size,
520
const char* msg)
521
{
522
int ret_val;
523
char err_msg[256];
524
errno = 0;
525
socket_closed = 0;
526
ret_val = oa_socket_write(sock->socket, buf, buf_size);
527
if (ret_val == -1) {
528
if (socket_closed) {
529
FD_CLR(sock->socket, &socket_mask);
530
purpose_table[sock->purpose] = NULL;
531
/* printf(" closing socket %d\n", sock->socket); */
532
oa_close_socket(sock->socket);
533
return wait_for_client_write(sock, buf, buf_size, msg);
534
} else {
535
if (msg) {
536
sprintf(err_msg, "writing: %s", msg);
537
perror(err_msg);
538
}
539
return -1;
540
}
541
}
542
return ret_val;
543
}
544
545
OPENAXIOM_C_EXPORT int
546
sselect(int n,fd_set *rd, fd_set *wr, fd_set *ex, void *timeout)
547
{
548
int ret_val;
549
do {
550
ret_val = select(n, rd, wr, ex, (struct timeval *) timeout);
551
} while (ret_val == -1 && openaxiom_syscall_was_cancelled());
552
return ret_val;
553
}
554
555
OPENAXIOM_C_EXPORT int
556
fill_buf(openaxiom_sio *sock, Byte* buf, int len, const char* msg)
557
{
558
int bytes = 0, ret_val;
559
while(bytes < len) {
560
ret_val = sread(sock, buf + bytes, len - bytes, msg);
561
if (ret_val == -1) return -1;
562
bytes += ret_val;
563
}
564
return bytes;
565
}
566
567
OPENAXIOM_C_EXPORT int
568
get_int(openaxiom_sio *sock)
569
{
570
int val = -1, len;
571
len = fill_buf(sock, byte_address(val), sizeof(int), "get_int");
572
if (len != sizeof(int)) {
573
#ifdef DEBUG
574
fprintf(stderr,"get_int: caught error\n",val);
575
#endif
576
return -1;
577
}
578
#ifdef DEBUG
579
fprintf(stderr,"get_int: received %d\n",val);
580
#endif
581
return val;
582
}
583
584
OPENAXIOM_C_EXPORT int
585
sock_get_int(int purpose)
586
{
587
if (accept_if_needed(purpose) != -1)
588
return get_int(purpose_table[purpose]);
589
else return -1;
590
}
591
592
OPENAXIOM_C_EXPORT int
593
get_ints(openaxiom_sio *sock, int *vals, int num)
594
{
595
int i;
596
for(i=0; i<num; i++)
597
*vals++ = get_int(sock);
598
return 0;
599
}
600
601
OPENAXIOM_C_EXPORT int
602
sock_get_ints(int purpose, int *vals, int num)
603
{
604
if (accept_if_needed(purpose) != -1)
605
return get_ints(purpose_table[purpose], vals, num);
606
return -1;
607
}
608
609
OPENAXIOM_C_EXPORT int
610
send_int(openaxiom_sio *sock,int val)
611
{
612
int ret_val;
613
ret_val = swrite(sock, byte_address(val), sizeof(int), "send_int");
614
if (ret_val == -1) {
615
return -1;
616
}
617
return 0;
618
}
619
620
OPENAXIOM_C_EXPORT int
621
sock_send_int(int purpose,int val)
622
{
623
if (accept_if_needed(purpose) != -1)
624
return send_int(purpose_table[purpose], val);
625
return -1;
626
}
627
628
OPENAXIOM_C_EXPORT int
629
send_ints(openaxiom_sio *sock, const int *vals, int num)
630
{
631
int i;
632
for(i=0; i<num; i++)
633
if (send_int(sock, *vals++) == -1)
634
return -1;
635
return 0;
636
}
637
638
OPENAXIOM_C_EXPORT int
639
sock_send_ints(int purpose, const int *vals, int num)
640
{
641
if (accept_if_needed(purpose) != -1)
642
return send_ints(purpose_table[purpose], vals, num);
643
return -1;
644
}
645
646
OPENAXIOM_C_EXPORT int
647
send_string_len(openaxiom_sio *sock, const char *str,int len)
648
{
649
int val;
650
if (len > 1023) {
651
char *buf;
652
buf = (char*) malloc(len+1);
653
strncpy(buf,str,len);
654
buf[len]='\0';
655
send_int(sock,len+1);
656
val = swrite(sock, (const Byte*) buf, len+1, "send_string_len");
657
free(buf);
658
} else {
659
static char buf[1024];
660
strncpy(buf, str, len);
661
buf[len] = '\0';
662
send_int(sock, len+1);
663
val = swrite(sock, (const Byte*) buf, len+1, "send_string_len");
664
}
665
if (val == -1) {
666
return val;
667
}
668
return 0;
669
}
670
671
OPENAXIOM_C_EXPORT int
672
send_string(openaxiom_sio* sock, const char* str)
673
{
674
int val, len = strlen(str);
675
send_int(sock, len+1);
676
val = swrite(sock, (const Byte*) str, len+1, "send_string");
677
if (val == -1) {
678
return -1;
679
}
680
return 0;
681
}
682
683
684
OPENAXIOM_C_EXPORT int
685
sock_send_string(int purpose, const char *str)
686
{
687
if (accept_if_needed(purpose) != -1)
688
return send_string(purpose_table[purpose], str);
689
return -1;
690
}
691
692
OPENAXIOM_C_EXPORT int
693
sock_send_string_len(int purpose, const char* str, int len)
694
{
695
if (accept_if_needed(purpose) != -1)
696
return send_string_len(purpose_table[purpose], str, len);
697
return -1;
698
}
699
700
OPENAXIOM_C_EXPORT int
701
send_strings(openaxiom_sio *sock, const char** vals, int num)
702
{
703
int i;
704
for(i=0; i<num; i++)
705
if (send_string(sock, *vals++) == -1)
706
return -1;
707
return 0;
708
}
709
710
OPENAXIOM_C_EXPORT int
711
sock_send_strings(int purpose, const char**vals, int num)
712
{
713
if (accept_if_needed(purpose) != -1)
714
return send_strings(purpose_table[purpose], vals, num);
715
return -1;
716
}
717
718
OPENAXIOM_C_EXPORT char *
719
get_string(openaxiom_sio *sock)
720
{
721
int val, len;
722
char *buf;
723
len = get_int(sock);
724
if (len <0) return NULL;
725
buf = (char*) malloc(len*sizeof(char));
726
val = fill_buf(sock, (Byte*) buf, len, "get_string");
727
if (val == -1){
728
free(buf);
729
return NULL;
730
}
731
#ifdef DEBUG
732
fprintf(stderr,"get_string: received \"%s\" \n",buf);
733
#endif
734
return buf;
735
}
736
737
OPENAXIOM_C_EXPORT char *
738
sock_get_string(int purpose)
739
{
740
if (accept_if_needed(purpose) != -1)
741
return get_string(purpose_table[purpose]);
742
else return NULL;
743
}
744
745
746
OPENAXIOM_C_EXPORT char *
747
get_string_buf(openaxiom_sio *sock, char *buf, int buf_len)
748
{
749
int nbytes_read;
750
int nbytes_to_read;
751
if(sock->nbytes_pending == 0)
752
sock->nbytes_pending = get_int(sock);
753
nbytes_to_read = sock->nbytes_pending > buf_len
754
? buf_len
755
: sock->nbytes_pending;
756
nbytes_read = fill_buf(sock, (Byte*)buf, nbytes_to_read,
757
"get_string_buf");
758
if (nbytes_read == -1) {
759
sock->nbytes_pending = 0;
760
return NULL;
761
}
762
sock->nbytes_pending -= nbytes_read;
763
return sock->nbytes_pending == 0 ? NULL : buf;
764
}
765
766
OPENAXIOM_C_EXPORT char *
767
sock_get_string_buf(int purpose, char* buf, int buf_len)
768
{
769
if (accept_if_needed(purpose) != -1)
770
return get_string_buf(purpose_table[purpose], buf, buf_len);
771
return NULL;
772
}
773
774
OPENAXIOM_C_EXPORT int
775
get_strings(openaxiom_sio *sock, char** vals,int num)
776
{
777
int i;
778
for(i=0; i<num; i++)
779
*vals++ = get_string(sock);
780
return 0;
781
}
782
783
OPENAXIOM_C_EXPORT int
784
sock_get_strings(int purpose, char** vals, int num)
785
{
786
if (accept_if_needed(purpose) != -1)
787
return get_strings(purpose_table[purpose], vals, num);
788
return -1;
789
}
790
791
OPENAXIOM_C_EXPORT int
792
send_float(openaxiom_sio *sock, double num)
793
{
794
int val;
795
val = swrite(sock, byte_address(num), sizeof(double),"send_float");
796
if (val == -1) {
797
return -1;
798
}
799
return 0;
800
}
801
802
OPENAXIOM_C_EXPORT int
803
sock_send_float(int purpose, double num)
804
{
805
if (accept_if_needed(purpose) != -1)
806
return send_float(purpose_table[purpose], num);
807
return -1;
808
}
809
810
OPENAXIOM_C_EXPORT int
811
send_sfloats(openaxiom_sio *sock, const float *vals,int num)
812
{
813
int i;
814
for(i=0; i<num; i++)
815
if (send_float(sock, (double) *vals++) == -1)
816
return -1;
817
return 0;
818
}
819
820
OPENAXIOM_C_EXPORT int
821
sock_send_sfloats(int purpose, const float* vals, int num)
822
{
823
if (accept_if_needed(purpose) != -1)
824
return send_sfloats(purpose_table[purpose], vals, num);
825
return -1;
826
}
827
828
OPENAXIOM_C_EXPORT int
829
send_floats(openaxiom_sio *sock, const double *vals, int num)
830
{
831
int i;
832
for(i=0; i<num; i++)
833
if (send_float(sock, *vals++) == -1)
834
return -1;
835
return 0;
836
}
837
838
OPENAXIOM_C_EXPORT int
839
sock_send_floats(int purpose, const double *vals, int num)
840
{
841
if (accept_if_needed(purpose) != -1)
842
return send_floats(purpose_table[purpose], vals, num);
843
return -1;
844
}
845
846
OPENAXIOM_C_EXPORT double
847
get_float(openaxiom_sio *sock)
848
{
849
double num = -1.0;
850
fill_buf(sock, byte_address(num), sizeof(double), "get_float");
851
#ifdef DEBUG
852
fprintf(stderr,"get_float: received %f\n",num);
853
#endif
854
return num;
855
}
856
857
OPENAXIOM_C_EXPORT double
858
sock_get_float(int purpose)
859
{
860
if (accept_if_needed(purpose) != -1)
861
return get_float(purpose_table[purpose]);
862
else return 0.0;
863
}
864
865
OPENAXIOM_C_EXPORT int
866
get_sfloats(openaxiom_sio *sock, float *vals, int num)
867
{
868
int i;
869
for(i=0; i<num; i++)
870
*vals++ = (float) get_float(sock);
871
return 0;
872
}
873
874
875
OPENAXIOM_C_EXPORT int
876
sock_get_sfloats(int purpose,float * vals, int num)
877
{
878
if (accept_if_needed(purpose) != -1)
879
return get_sfloats(purpose_table[purpose], vals, num);
880
return -1;
881
}
882
883
OPENAXIOM_C_EXPORT int
884
get_floats(openaxiom_sio *sock,double *vals,int num)
885
{
886
int i;
887
for(i=0; i<num; i++)
888
*vals++ = get_float(sock);
889
return 0;
890
}
891
892
893
OPENAXIOM_C_EXPORT int
894
sock_get_floats(int purpose, double *vals, int num)
895
{
896
if (accept_if_needed(purpose) != -1)
897
return get_floats(purpose_table[purpose], vals, num);
898
return -1;
899
}
900
901
OPENAXIOM_C_EXPORT int
902
wait_for_client_kill(openaxiom_sio *sock, int sig)
903
{
904
int ret_val;
905
switch(sock->purpose) {
906
case SessionManager:
907
case ViewportServer:
908
sock_accept_connection(sock->purpose);
909
ret_val = send_signal(purpose_table[sock->purpose], sig);
910
sock->socket = 0;
911
return ret_val;
912
default:
913
sock->socket = 0;
914
return -1;
915
}
916
}
917
918
919
OPENAXIOM_C_EXPORT int
920
sock_get_remote_fd(int purpose)
921
{
922
if (accept_if_needed(purpose) != -1)
923
return purpose_table[purpose]->remote;
924
return -1;
925
}
926
927
OPENAXIOM_C_EXPORT int
928
send_signal(openaxiom_sio *sock, int sig)
929
{
930
int ret_val;
931
#if HAVE_DECL_KILL
932
ret_val = kill(sock->pid, sig);
933
#else
934
ret_val = raise(sig);
935
#endif
936
if (ret_val == -1 && errno == ESRCH) {
937
FD_CLR(sock->socket, &socket_mask);
938
purpose_table[sock->purpose] = NULL;
939
/* printf(" closing socket %d\n", sock->socket); */
940
oa_close_socket(sock->socket);
941
return wait_for_client_kill(sock, sig);
942
}
943
return ret_val;
944
}
945
946
OPENAXIOM_C_EXPORT int
947
sock_send_signal(int purpose,int sig)
948
{
949
if (accept_if_needed(purpose) != -1)
950
return send_signal(purpose_table[purpose], sig);
951
return -1;
952
}
953
954
OPENAXIOM_C_EXPORT int
955
send_wakeup(openaxiom_sio *sock)
956
{
957
#ifdef SIGUSR1
958
return send_signal(sock, SIGUSR1);
959
#else
960
return -1;
961
#endif
962
}
963
964
OPENAXIOM_C_EXPORT int
965
sock_send_wakeup(int purpose)
966
{
967
if (accept_if_needed(purpose) != -1)
968
return send_wakeup(purpose_table[purpose]);
969
return -1;
970
}
971
972
OPENAXIOM_C_EXPORT openaxiom_sio *
973
connect_to_local_server_new(const char *server_name, int purpose, int time_out)
974
{
975
int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1;
976
openaxiom_sio *sock;
977
char name[256];
978
979
make_server_name(name, server_name);
980
sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1);
981
if (sock == NULL) {
982
perror("allocating socket space");
983
return NULL;
984
}
985
986
sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL);
987
if (is_invalid_socket(sock)) {
988
perror("opening client socket");
989
free(sock);
990
return NULL;
991
}
992
993
memset(server.addr.u_addr.sa_data, 0,
994
sizeof(server.addr.u_addr.sa_data));
995
sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL;
996
strcpy(sock->addr.u_addr.sa_data, name);
997
for(i=0; i<max_con; i++) {
998
code = connect(sock->socket, &sock->addr.u_addr,
999
sizeof(sock->addr.u_addr));
1000
if (code == -1) {
1001
if (errno != ENOENT && !openaxiom_connection_refused()) {
1002
perror("connecting server stream socket");
1003
return NULL;
1004
} else {
1005
if (i != max_con - 1)
1006
openaxiom_sleep(1);
1007
continue;
1008
}
1009
} else break;
1010
}
1011
1012
if (code == -1) {
1013
return NULL;
1014
}
1015
1016
send_int(sock, oa_getpid());
1017
send_int(sock, purpose);
1018
send_int(sock, sock->socket);
1019
sock->pid = get_int(sock);
1020
sock->remote = get_int(sock);
1021
return sock;
1022
}
1023
1024
OPENAXIOM_C_EXPORT openaxiom_sio *
1025
connect_to_local_server(const char *server_name, int purpose, int time_out)
1026
{
1027
int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1;
1028
openaxiom_sio *sock;
1029
char name[256];
1030
1031
make_server_name(name, server_name);
1032
sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1);
1033
if (sock == NULL) {
1034
perror("allocating socket space");
1035
return NULL;
1036
}
1037
1038
sock->purpose = purpose;
1039
/* create the socket */
1040
sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL);
1041
if (is_invalid_socket(sock)) {
1042
perror("opening client socket");
1043
free(sock);
1044
return NULL;
1045
}
1046
/* connect socket using name specified in command line */
1047
memset(server.addr.u_addr.sa_data, 0,
1048
sizeof(server.addr.u_addr.sa_data));
1049
sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL;
1050
strcpy(sock->addr.u_addr.sa_data, name);
1051
for(i=0; i<max_con; i++) {
1052
code = connect(sock->socket, &sock->addr.u_addr,
1053
sizeof(sock->addr.u_addr));
1054
if (code == -1) {
1055
if (errno != ENOENT && !openaxiom_connection_refused()) {
1056
perror("connecting server stream socket");
1057
return NULL;
1058
} else {
1059
if (i != max_con - 1)
1060
openaxiom_sleep(1);
1061
continue;
1062
}
1063
} else break;
1064
}
1065
if (code == -1) {
1066
return NULL;
1067
}
1068
send_int(sock, oa_getpid());
1069
send_int(sock, sock->purpose);
1070
send_int(sock, sock->socket);
1071
sock->pid = get_int(sock);
1072
/* fprintf(stderr, "Got int form socket\n"); */
1073
sock->remote = get_int(sock);
1074
return sock;
1075
}
1076
1077
/* act as terminal session for sock connected to stdin and stdout of another
1078
process */
1079
OPENAXIOM_C_EXPORT void
1080
remote_stdio(openaxiom_sio *sock)
1081
{
1082
char buf[1024];
1083
fd_set rd;
1084
int len;
1085
while (1) {
1086
FD_ZERO(&rd);
1087
FD_SET(sock->socket,&rd);
1088
FD_SET(0, &rd);
1089
len = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL);
1090
if (len == -1) {
1091
perror("stdio select");
1092
return;
1093
}
1094
if (FD_ISSET(0, &rd)) {
1095
fgets(buf,1024,stdin);
1096
len = strlen(buf);
1097
swrite(sock, byte_address(buf), len, "remote_stdio::write");
1098
}
1099
if (FD_ISSET(sock->socket, &rd)) {
1100
len = sread(sock, byte_address(buf), 1024, "remote_stdio::read");
1101
if (len == -1)
1102
return;
1103
else {
1104
*(buf + len) = '\0';
1105
fputs(buf, stdout);
1106
fflush(stdout);
1107
}
1108
}
1109
}
1110
}
1111
1112
/* initialize the table of dedicated sockets */
1113
static void
1114
init_purpose_table()
1115
{
1116
int i;
1117
for(i=0; i<TotalMaxPurposes; i++) {
1118
purpose_table[i] = NULL;
1119
}
1120
}
1121
1122
1123
OPENAXIOM_C_EXPORT int
1124
make_server_number()
1125
{
1126
spad_server_number = oa_getpid();
1127
return spad_server_number;
1128
}
1129
1130
OPENAXIOM_C_EXPORT void
1131
close_socket(openaxiom_socket socket_num, const char *name)
1132
{
1133
oa_close_socket(socket_num);
1134
oa_unlink(name);
1135
}
1136
1137
OPENAXIOM_C_EXPORT int
1138
make_server_name(char *name, const char* base)
1139
{
1140
char *num;
1141
if (spad_server_number != -1) {
1142
sprintf(name, "%s%d", base, spad_server_number);
1143
return 0;
1144
}
1145
num = oa_getenv("SPADNUM");
1146
if (num == NULL) {
1147
/* fprintf(stderr,
1148
"\n(AXIOM Sockets) The AXIOM server number is undefined.\n");
1149
*/
1150
return -1;
1151
}
1152
sprintf(name, "%s%s", base, num);
1153
return 0;
1154
}
1155
1156
static void
1157
init_socks()
1158
{
1159
FD_ZERO(&socket_mask);
1160
FD_ZERO(&server_mask);
1161
init_purpose_table();
1162
server.socket = 0;
1163
for (int i=0; i<MaxClients; i++)
1164
clients[i].socket = 0;
1165
}
1166
1167
/* client Spad server sockets: server is a local domain socket. */
1168
OPENAXIOM_C_EXPORT int
1169
open_server(const char* server_name)
1170
{
1171
char *s, name[256];
1172
1173
init_socks();
1174
#ifdef SIGPIPE
1175
bsdSignal(SIGPIPE, sigpipe_handler,RestartSystemCalls);
1176
#endif
1177
if (make_server_name(name, server_name) == -1)
1178
return -2;
1179
/* Next create the local domain socket */
1180
server.socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL);
1181
if (is_invalid_socket(&server)) {
1182
perror("opening local server socket");
1183
server.socket = 0;
1184
return -2;
1185
} else {
1186
server.addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL;
1187
memset(server.addr.u_addr.sa_data, 0,
1188
sizeof(server.addr.u_addr.sa_data));
1189
strcpy(server.addr.u_addr.sa_data, name);
1190
if (bind(server.socket, &server.addr.u_addr,
1191
sizeof(server.addr.u_addr))) {
1192
perror("binding local server socket");
1193
server.socket = 0;
1194
return -2;
1195
}
1196
FD_SET(server.socket, &socket_mask);
1197
FD_SET(server.socket, &server_mask);
1198
listen(server.socket, 5);
1199
}
1200
s = oa_getenv("SPADSERVER");
1201
if (s == NULL) {
1202
/* fprintf(stderr, "Not a spad server system\n"); */
1203
return -1;
1204
}
1205
return 0;
1206
}
1207
1208
/* reads a the socket purpose declaration for classification */
1209
OPENAXIOM_C_EXPORT void
1210
get_socket_type(openaxiom_sio *sock)
1211
{
1212
sock->pid = get_int(sock);
1213
sock->purpose = get_int(sock);
1214
sock->remote = get_int(sock);
1215
send_int(sock, oa_getpid());
1216
send_int(sock, sock->socket);
1217
purpose_table[sock->purpose] = sock;
1218
}
1219
1220
OPENAXIOM_C_EXPORT int
1221
accept_connection()
1222
{
1223
int client = 0;
1224
while (client < MaxClients && clients[client].socket != 0)
1225
++client;
1226
if (client == MaxClients) {
1227
printf("Ran out of client openaxiom_sio structures\n");
1228
return -1;
1229
}
1230
clients[client].socket = accept(server.socket, 0, 0);
1231
if (is_invalid_socket(&clients[client])) {
1232
perror("accept_connection");
1233
clients[client].socket = 0;
1234
return -1;
1235
}
1236
FD_SET(clients[client].socket, &socket_mask);
1237
get_socket_type(&clients[client]);
1238
return clients[client].purpose;
1239
}
1240
1241
OPENAXIOM_C_EXPORT int
1242
sock_accept_connection(int purpose)
1243
{
1244
fd_set rd;
1245
int ret_val, p;
1246
if (oa_getenv("SPADNUM") == NULL) return -1;
1247
while (1) {
1248
rd = server_mask;
1249
ret_val = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL);
1250
if (ret_val == -1) {
1251
perror ("Select");
1252
return -1;
1253
}
1254
if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) {
1255
p = accept_connection();
1256
if (p == purpose) return 1;
1257
}
1258
}
1259
}
1260
1261
/* Socket I/O selection called from the BOOT serverLoop function */
1262
1263
OPENAXIOM_C_EXPORT int
1264
server_switch()
1265
{
1266
int ret_val, cmd = 0;
1267
fd_set rd, wr, ex, fds_mask;
1268
FD_ZERO(&rd);
1269
FD_ZERO(&wr);
1270
FD_ZERO(&ex);
1271
fds_mask = server_mask;
1272
cmd = 0;
1273
if (purpose_table[SessionManager] != NULL) {
1274
FD_SET(0, &fds_mask);
1275
FD_SET(purpose_table[SessionManager]->socket, &fds_mask);
1276
}
1277
while (1) {
1278
do {
1279
if (purpose_table[MenuServer] != NULL) {
1280
FD_SET(purpose_table[MenuServer]->socket, &fds_mask);
1281
}
1282
rd = fds_mask;
1283
ret_val = select(FD_SETSIZE, &rd, 0, 0, 0);
1284
if (ret_val == -1) {
1285
/* perror ("Select in switch"); */
1286
return -1;
1287
}
1288
if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd))
1289
accept_connection();
1290
} while (purpose_table[SessionManager] == NULL);
1291
FD_SET(purpose_table[SessionManager]->socket, &fds_mask);
1292
if (FD_ISSET(purpose_table[SessionManager]->socket, &rd)) {
1293
cmd = get_int(purpose_table[SessionManager]);
1294
return cmd;
1295
}
1296
if (FD_ISSET(0, &rd)) {
1297
return CallInterp;
1298
}
1299
if (purpose_table[MenuServer] != NULL &&
1300
(FD_ISSET(purpose_table[MenuServer]->socket, &rd))) {
1301
cmd = get_int(purpose_table[MenuServer]);
1302
return cmd;
1303
}
1304
}
1305
}
1306
1307
}
1308
1309