/
unix_sockets.p
741 lines (633 loc) · 19.8 KB
/
unix_sockets.p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
/* --- Copyright University of Sussex 2004. All rights reserved. ----------
> File: C.unix/lib/lib/unix_sockets.p
> Purpose: Unix socket interface
> Author: John Gibson May 6 1994 (see revisions)
> Documentation:
*/
compile_mode :pop11 +strict;
include sysdefs.ph;
#_IF not(DEF BERKELEY or DEFV SYSTEM_V >= 4.0)
#_TERMIN_IF DEF POPC_COMPILING
mishap(0, 'SOCKETS NOT SUPPORTED IN THIS SYSTEM');
#_ENDIF
section;
exload_batch;
include unix_sockets.ph;
include unix_errno.ph;
l_typespec
sockaddr_un
{ sun_family :short,
sun_path :byte[].exacc_ntstring
},
sockaddr_in
{ sin_family :short,
sin_port :ushort,
sin_addr_b :byte[0], ;;; dummy for getting byte addr of sin_addr
sin_addr :uint,
sin_zero :byte[8]
},
hostent
{ h_name !exptr,
h_aliases !exptr,
h_addrtype !int,
h_length !int,
h_addr !exptr.:exptr
},
servent
{ s_name !exptr,
s_aliases !exptr,
s_port !int,
s_proto !exptr.exacc_ntstring.consword
},
protoent
{ p_name !exptr,
p_aliases !exptr,
p_proto !int
},
netent
{ n_name !exptr,
n_aliases !exptr,
n_addrtype !int,
n_net !uint
}
;
exload unix_sockets
#_IF DEFV SYSTEM_V >= 4.0 or DEF SCO
['-lsocket']
#_ENDIF
lconstant
U_close(fd) :int <- close,
U_socket(af,type,protocol) :int <- socket,
U_socketpair(af,type,protocol,sv) :int <- socketpair,
U_getsockname(s,name,namelenp) :int <- getsockname,
U_getpeername(s,name,namelenp) :int <- getpeername,
U_bind(s,name,namelen) :int <- bind,
U_connect(s,name,namelen) :int <- connect,
U_listen(s,qlen) :int <- listen,
U_accept(s,name,namelenp) :int <- accept,
U_shutdown(s,how) :int <- shutdown,
U_getsockopt(s,level,option,valp,lenp) :int <- getsockopt,
U_setsockopt(s,level,option,valp,len) :int <- setsockopt,
U_gethostbyname(name) :exptr.:hostent <- gethostbyname,
U_getservbyname(name,proto) :exptr.:servent <- getservbyname,
U_getprotobyname(name) :exptr.:protoent <- getprotobyname,
U_getnetbyname(name) :exptr.:netent <- getnetbyname,
U_inet_ntoa(in) :exptr.exacc_ntstring <- inet_ntoa,
U_inet_addr(cp) :uint <- inet_addr,
U_inet_makeaddr(net,lna) :uint <- inet_makeaddr,
U_recv(s,buf,len,flags) :int <- recv,
U_recvfrom(s,buf,len,flags,from,fromlenp) :int <- recvfrom,
U_send(s,buf,len,flags) :int <- send,
U_sendto(s,buf,len,flags,to,tolen) :int <- sendto,
U_htons(val) :ushort <- htons,
U_htonl(val) :uint <- ntohl,
U_ntohs(val) :ushort <- ntohs,
U_ntohl(val) :uint <- ntohl,
;;; This is no longer supported. See revision notes
;;; U_errno :int <- errno,
pop_call_in_addr_arg(inp,func) :exptr,
pop_call_in_addr_res(net,lna,inp,func),
#_IF DEF OSF1
_pop_sigmask(block) :void,
#_ENDIF
endexload;
lconstant macro (
SOL_SOCKET = 16:FFFF, ;;; options for socket level
;;; see $popsrc/errors.p for definition of DO_ERRNO_VAL
ERRNO = [DO_ERRNO_VAL],
NAMEBUF_SIZE = 256,
);
lconstant
intvec1 = writeable initintvec(1),
intvec2 = writeable initintvec(2),
;
define :inline lconstant HTONS(val);
(exacc U_htons(val) fi_&& 16:FFFF)
enddefine;
define :inline lconstant HTONL(val);
exacc U_htonl(val)
enddefine;
define :inline lconstant NTOHS(val);
(exacc U_ntohs(val) fi_&& 16:FFFF)
enddefine;
define :inline lconstant NTOHL(val);
exacc U_ntohl(val)
enddefine;
;;; --- NAME <-> SOCKADDR MAPPING -----------------------------------------
;;; AF_UNIX
define lconstant name_to_sa_UNIX(name) -> (sockaddr_un, namesize);
lvars name, sockaddr_un, namesize;
sysfileok(name) -> name;
SIZEOFTYPE(:short) + datalength(name) -> namesize;
initexptr_mem(namesize+1) -> sockaddr_un;
AF_UNIX -> exacc sockaddr_un.sun_family;
name -> exacc sockaddr_un.sun_path
enddefine;
;;;
define updaterof name_to_sa_UNIX(sockaddr_un, namesize) /* -> name */;
lvars sockaddr_un, namesize;
exacc sockaddr_un.sun_path
enddefine;
;;; AF_INET
define lconstant inet_name_to_sa(name) -> (sockaddr_in, namesize, proto);
lvars name, sockaddr_in, namesize, addr, hostent, servent,
netent, lna, port = 0, org_name = name, proto = false;
define inv_name(ms);
lvars ms;
mishap(org_name, 1, 'INVALID INTERNET SOCKET NAME (' <> ms <> ')')
enddefine;
define call_getbyname(func, name);
#_IF DEF OSF1
;;; OSF doesn't deal properly with EINTR inside gethostbyname
dlocal 0 %exacc _pop_sigmask(1), exacc _pop_sigmask(0) %;
#_ENDIF
exacc (1):exptr func(name)
enddefine;
SIZEOFTYPE(:sockaddr_in) -> namesize;
initexptr_mem(namesize) -> sockaddr_in;
0 -> port;
if islist(name) then
if listlength(name) == 2 then
dl(name) -> (name, port);
unless isinteger(port) then
if isvector(port) then
if datalength(port) == 2 then
explode(port) -> (port, proto)
else
inv_name('invalid service vector')
endif
endif;
if isword(proto) then fast_word_string(proto) -> proto endif;
if isstring(port) and (not(proto) or isstring(proto)) then
;;; service spec
exacc U_getservbyname(port, proto) -> servent;
unless is_valid_external_ptr(servent) then
inv_name('unknown server')
endunless;
exacc servent.s_proto -> proto;
NTOHS(exacc servent.s_port) -> port
elseif isstring(proto) then
consword(proto) -> proto
endif
endunless;
unless isinteger(port) and port >= 0 then
inv_name('invalid port')
endunless
else
inv_name('invalid host/port list')
endif
endif;
if name == "*" then INADDR_ANY -> name endif;
if isvector(name) then
;;; net spec
INADDR_ANY -> lna;
if datalength(name) == 2 then
explode(name) -> (name, lna)
else
inv_name('invalid net address vector')
endif;
if isstring(name) then
call_getbyname(U_getnetbyname, name) -> netent;
unless is_valid_external_ptr(netent)
and exacc netent.n_addrtype == AF_INET then
inv_name('unknown or invalid network name')
endunless;
exacc netent.n_net -> name
endif;
unless isinteger(name) and isinteger(lna) then
inv_name('invalid net and/or local address part')
endunless;
exacc pop_call_in_addr_res(name, lna,
exacc[@,nc] sockaddr_in.sin_addr, U_inet_makeaddr)
elseif isstring(name) then
;;; try numeric notation first
if datalength(name) /== 0 and isnumbercode(name(1))
and (exacc U_inet_addr(name) ->> addr) /= 16:FFFFFFFF then
addr -> exacc sockaddr_in.sin_addr
else
;;; try as hostname
call_getbyname(U_gethostbyname, name) -> hostent;
unless is_valid_external_ptr(hostent)
and exacc hostent.h_addrtype == AF_INET then
inv_name('unknown or invalid hostname')
endunless;
move_bytes( 1, exacc[nc] hostent.h_addr,
1, exacc[nc] sockaddr_in.sin_addr_b,
SIZEOFTYPE(:uint))
endif
elseif isintegral(name) and name >= 0 then
HTONL(name) -> exacc sockaddr_in.sin_addr
else
inv_name('address not a string or (big)integer >= 0')
endif;
HTONS(port) -> exacc sockaddr_in.sin_port;
set_bytes(0, 1, exacc[nc] sockaddr_in.sin_zero, 8);
AF_INET -> exacc sockaddr_in.sin_family
enddefine;
define lconstant name_to_sa_INET = inet_name_to_sa <> erase enddefine;
;;;
define updaterof name_to_sa_INET(sockaddr_in, namesize) /* -> name */;
lvars sockaddr_in, namesize, inaddr, port;
NTOHS(exacc sockaddr_in.sin_port) -> port;
returnif(port == 0) (false);
NTOHL(exacc sockaddr_in.sin_addr) -> inaddr;
if inaddr == INADDR_ANY then
"*"
else
exacc_ntstring(exacc pop_call_in_addr_arg(
exacc[@,nc] sockaddr_in.sin_addr, U_inet_ntoa))
endif -> inaddr;
if port == 0 then
inaddr
else
[^inaddr ^port]
endif
enddefine;
define sys_socket_name_trans =
newassoc([
[^AF_UNIX ^name_to_sa_UNIX]
[^AF_INET ^name_to_sa_INET]
])
enddefine;
lconstant
noname_ms = 'NO NAME TRANSLATION AVAILABLE FOR SOCKET ADDRESS FAMILY';
define lconstant name_to_sockaddr(name, af) /* -> (namebuf, namesize) */;
lvars name, af, trans_p;
if sys_socket_name_trans(af) ->> trans_p then
chain(name, trans_p)
else
mishap(af, 1, noname_ms)
endif
enddefine;
define lconstant sockaddr_to_name(namebuf, namesize) /* -> name */;
lvars namebuf, namesize, trans_p, af = exacc :short namebuf;
if sys_socket_name_trans(af) ->> trans_p then
chain(namebuf, namesize, updater(trans_p))
elseif af == AF_UNSPEC then
false
else
mishap(af, 1, noname_ms)
endif
enddefine;
;;; --- SOCKET CREATION -------------------------------------------------
define lconstant is_socket =
newproperty([], 8, false, "tmparg")
enddefine;
define lconstant check_sock(sock) /* -> af */;
lvars sock, svec;
if is_socket(sock) ->> svec then
svec(1) ;;; af
else
mishap(sock, 1, 'SOCKET NEEDED')
endif
enddefine;
define lconstant open_socks(af, type, protocol, routine) -> res;
lvars af, type, protocol, res, routine, retry = 1,
clex = (routine == U_socket);
repeat
exacc (4):int routine(af, type, protocol, intvec2) -> res;
quitif((Sys_fd_open_check(res, clex, retry) ->> retry) < 0)
endrepeat;
if res < 0 then
mishap(af, type, protocol, 3, '%CAN\'T CREATE SOCKET(S) (%M)')
endif
enddefine;
define lconstant proto_number(proto) -> protonum;
lvars proto, protonum, protoent;
define lconstant cache = newassoc([]) enddefine;
returnif(cache(proto) ->> protonum);
exacc U_getprotobyname(fast_word_string(proto)) -> protoent;
if is_valid_external_ptr(protoent) then
exacc protoent.p_proto -> protonum
elseunless (strnumber(proto) ->> protonum) and isinteger(protonum)
and protonum >= 0 then
mishap(proto, 1, 'UNKNOWN OR INVALID PROTOCOL NAME')
endif;
protonum -> cache(proto)
enddefine;
define lconstant create_socks(af, type, routine) /* -> (res,svec) */;
lvars af, type, routine, protocol = 0, protoent;
if isword(type) then
;;; optional protocol specified
((), af, type) -> (af, type, protocol);
proto_number(protocol) -> protocol
endif;
checkinteger(af, 0, false);
if af == `u` then
AF_UNIX -> af
elseif af == `i` then
AF_INET -> af
endif;
checkinteger(type, 0, false);
if type == `S` then
SOCK_STREAM -> type
elseif type == `D` then
SOCK_DGRAM -> type
endif;
open_socks(af, type, protocol, routine),
consvector(af, type, protocol, 3)
enddefine;
define lconstant make_sock_dev(fd, svec, org) -> sock;
lvars fd, svec, org,
sock = Sys_cons_device('socket', false, 2, org, fd, true);
svec -> is_socket(sock)
enddefine;
define sys_socket(/*af, type,*/ org) with_nargs 4;
lvars org;
make_sock_dev(create_socks((), U_socket), org)
enddefine;
define sys_socket_pair(/*af, type,*/ org) with_nargs 4;
lvars org, s1, s2, (, svec) = create_socks((), U_socketpair);
explode(intvec2) -> (s1, s2);
make_sock_dev(s1, svec, org);
make_sock_dev(s2, svec, org);
enddefine;
;;; --- SOCKET NAMES ---------------------------------------------------
define lconstant get_sock_name(sock, routine) -> name;
lvars sock, routine, af = check_sock(sock), res, name, retry = 1,
namebuf = EXPTRINITSTR(:byte[NAMEBUF_SIZE]);
repeat
NAMEBUF_SIZE -> intvec1(1);
exacc (3):int routine(device_os_channel(sock), namebuf, intvec1) -> res;
quitif((Sys_fd_open_check(res, false, retry) ->> retry) < 0)
endrepeat;
if res >= 0 then
sockaddr_to_name(namebuf, intvec1(1))
elseif ERRNO == ENOTCONN then
false
else
mishap(sock, 1, '%CAN\'T GET SOCKET NAME (%M)')
endif -> name;
sys_grbg_fixed(namebuf)
enddefine;
define sys_socket_name(sock) /* -> name */;
lvars sock;
get_sock_name(sock, U_getsockname)
enddefine;
;;;
define updaterof sys_socket_name(name, sock);
lvars name, sock, res, retry = 1, qlen = false, fd, namebuf, namesize;
if isinteger(sock) then
;;; queue length specified -- start listening after bind
((), name, sock) -> (name, sock, qlen);
checkinteger(qlen, 1, false)
endif;
name_to_sockaddr(name, check_sock(sock)) -> (namebuf, namesize);
device_os_channel(sock) -> fd;
repeat
exacc U_bind(fd, namebuf, namesize) -> res;
quitif((Sys_fd_open_check(res, false, retry) ->> retry) < 0)
endrepeat;
sys_grbg_fixed(namebuf);
if res < 0 then
mishap(name, sock, 2, '%CAN\'T ASSIGN SOCKET NAME (%M)')
endif;
if qlen and exacc U_listen(fd, qlen) < 0 then
mishap(name, sock, qlen, 3, '%LISTEN FAILED ON SOCKET (%M)')
endif
enddefine;
define lconstant do_connect(peername, sock, namebuf, namesize, changes_p,
conn_retries);
lvars peername, sock, res, retry, namebuf, namesize, conn_retries,
changes_p, fd = device_os_channel(sock),
sockname = sys_socket_name(sock), connect_started;
repeat
changes_p(sock);
false -> connect_started;
1 -> retry;
repeat
repeat
exacc U_connect(fd, namebuf, namesize) -> res;
quitif((Sys_fd_open_check(res, false, retry) ->> retry) < 0);
;;; An interrupt means the connection attempt may have
;;; actually started, so just wait after EALREADY, and
;;; take EISCONN to mean success
if res < 0 and ERRNO == EINTR then
true -> connect_started
endif
endrepeat;
quitif(res >= 0) (2); ;;; success
quitunless(connect_started);
if ERRNO == EISCONN then
;;; take this to mean success
0 -> res;
quitloop(2)
endif;
;;; HPUX (possibly others?) returns EADDRINUSE instead of EALREADY,
;;; so test for them both ...
quitunless(ERRNO == EALREADY or ERRNO == EADDRINUSE);
;;; else wait a bit if already in progress
syssleep(50)
endrepeat;
;;; come here for (genuine) error
quitunless(ERRNO == ECONNREFUSED);
;;; ECONNREFUSED -- fd of socket is now useless, so must close it
;;; and create another
while Sys_fd_open_check(exacc U_close(fd), false, 0) == 0 do endwhile;
open_socks(explode(is_socket(sock)), U_socket)
->> fd -> device_os_channel(sock);
if sockname then sockname -> sys_socket_name(sock) endif;
if conn_retries == 0 then
mishap(peername, sock, 2, 'CAN\'T ASSIGN SOCKET PEERNAME (Connection refused)')
endif;
conn_retries-1 -> conn_retries;
;;; wait a sec and try again with the new socket
syssleep(100)
endrepeat;
returnunless(namebuf);
sys_grbg_fixed(namebuf);
if res < 0 then
mishap(peername, sock, 2, '%CAN\'T ASSIGN SOCKET PEERNAME (%M)')
endif
enddefine;
define sys_socket_peername(sock) /* -> peername */;
lvars sock;
get_sock_name(sock, U_getpeername)
enddefine;
;;;
define updaterof sys_socket_peername(peername, sock);
lvars peername, sock, namebuf, namesize, af, conn_retries = 5, p = erase;
if isinteger(sock) then
;;; optional connect retry count
((), peername, sock) -> (peername, sock, conn_retries);
checkinteger(conn_retries, 1, false)
endif;
if isprocedure(sock) then
;;; optional procedure to apply to sock before connect attempt
((), peername, sock) -> (peername, sock, p)
endif;
check_sock(sock) -> af;
if peername or is_socket(sock)(2) /== SOCK_DGRAM then
name_to_sockaddr(peername, af)
else
;;; false for SOCK_DGRAM
false, 0
endif -> (namebuf, namesize);
do_connect(peername, sock, namebuf, namesize, p, conn_retries)
enddefine;
;;; --- OTHER ROUTINES ---------------------------------------------------
define sys_socket_to_service(peername, org) -> sock;
lvars peername, org, sock, type,
(namebuf, namesize, proto) = inet_name_to_sa(peername);
unless proto then
mishap(peername, 1, 'INTERNET SERVICE NAME NEEDED')
endunless;
if proto = "tcp" then
SOCK_STREAM
elseif proto = "udp" then
SOCK_DGRAM
else
mishap(peername, 1, 'SERVICE PROTOCOL NOT tcp OR udp')
endif -> type;
sys_socket(AF_INET, type, org) -> sock;
do_connect(peername, sock, namebuf, namesize, erase, 5)
enddefine;
define sys_socket_accept(sock, org) /* -> conn_sock */;
lvars sock, org;
check_sock(sock) -> ;
procedure();
lvars fd = device_os_channel(sock), cfd, retry = 1;
dlocal % sys_async_io(sock, 0) % = false;
;;; wait for connection in X if running ...
sys_device_wait(sock, [], [], true) -> (,,);
repeat
exacc U_accept(fd, dup(null_external_ptr)) -> cfd;
quitif((Sys_fd_open_check(cfd, false, retry) ->> retry) < 0)
endrepeat;
if cfd < 0 then
mishap(sock, 1, '%ACCEPT FAILED ON SOCKET (%M)')
else
make_sock_dev(cfd, is_socket(sock), org)
endif
endprocedure()
enddefine;
define sys_socket_shutdown(sock, how);
lvars sock, how;
check_sock(sock) -> ;
checkinteger(how, 0, 2);
if exacc U_shutdown(device_os_channel(sock), how) < 0 then
mishap(sock, how, 2, '%SHUTDOWN FAILED ON SOCKET (%M)')
endif
enddefine;
;;; --- SEND AND RECEIVE -----------------------------------------------
define lconstant get_option_args(sock, option) -> (option, level, bool);
lvars sock, option, level = SOL_SOCKET, bool = true;
check_sock(sock) -> ;
checkinteger(option, 0, false);
if option &&/=_0 TCPBIT then
option &&~~ TCPBIT -> option;
proto_number("tcp") -> level
endif;
if option &&/=_0 INTBIT then
option &&~~ INTBIT -> option;
false -> bool
endif
enddefine;
define sys_socket_option(sock, option) -> value;
lvars sock, option, value, res,
(opt, level, bool) = get_option_args(sock, option);
SIZEOFTYPE(:int[2]) -> intvec1(1);
exacc U_getsockopt(device_os_channel(sock), level, opt, intvec2, intvec1)
-> res;
if res < 0 then
mishap(sock, option, 2, '%ERROR GETTING SOCKET OPTION (%M)')
endif;
intvec2(1) -> value;
if option == SO_LINGER then
value /== 0 and intvec2(2) -> value
elseif bool then
value /== 0 -> value
endif
enddefine;
;;;
define updaterof sys_socket_option(value, sock, option);
lvars value, sock, option, res, len = SIZEOFTYPE(:int),
(opt, level, bool) = get_option_args(sock, option);
if option == SO_LINGER then
SIZEOFTYPE(:int[2]) -> len;
if value then 1, value else 0, 0 endif -> intvec2(2);
elseif bool then
if value then 1 else 0 endif
else
value
endif -> intvec2(1);
exacc U_setsockopt(device_os_channel(sock), level, opt, intvec2, len)
-> res;
if res < 0 then
mishap(sock, option, 2, '%ERROR SETTING SOCKET OPTION (%M)')
endif
enddefine;
define sys_socket_recv(sock, buff, nbytes, flags, want_fromname);
lvars sock, buff, nbytes, flags, want_fromname, fd, res, namebuf;
check_sock(sock) -> ;
check_string(buff);
checkinteger(nbytes, 0, false);
checkinteger(flags, 0, false);
device_os_channel(sock) -> fd;
if want_fromname then
EXPTRINITSTR(:byte[NAMEBUF_SIZE]) -> namebuf
endif;
repeat
if want_fromname then
NAMEBUF_SIZE -> intvec1(1);
exacc U_recvfrom(fd, buff, nbytes, flags, namebuf, intvec1)
else
exacc U_recv(fd, buff, nbytes, flags)
endif -> res;
quitif(res >= 0);
nextif(ERRNO == EINTR);
mishap(sock, 1, '%ERROR RECEIVING FROM SOCKET (%M)')
endrepeat;
if want_fromname then
res, sockaddr_to_name(namebuf, intvec1(1));
sys_grbg_fixed(namebuf)
else
res
endif
enddefine;
define sys_socket_send(sock, buff, nbytes, flags, toname);
lvars sock, buff, nbytes, flags, toname, fd, res, namebuf, namesize, af;
check_sock(sock) -> af;
check_string(buff);
checkinteger(nbytes, 0, false);
checkinteger(flags, 0, false);
device_os_channel(sock) -> fd;
if toname then
name_to_sockaddr(toname, af) -> (namebuf, namesize)
endif;
repeat
if toname then
exacc U_sendto(fd, buff, nbytes, flags, namebuf, namesize)
else
exacc U_send(fd, buff, nbytes, flags)
endif -> res;
quitif(res >= 0);
nextif(ERRNO == EINTR);
mishap(sock, 1, '%ERROR SENDING TO SOCKET (%M)')
endrepeat;
if toname then sys_grbg_fixed(namebuf) endif
enddefine;
constant unix_sockets = true;
endexload_batch;
endsection;
/* --- Revision History ---------------------------------------------------
--- Aaron Sloman, Dec 31 2004
Redefined ERRNO to correspond to changes made to system sources
in $popexternlib/c_core.c, $popsrc/unixdefs.ph $popsrc/errors.p
--- John Gibson, May 13 1998
__pop_call_in_addr_res/arg -> pop_call_in_addr_res/arg
--- John Gibson, Mar 12 1997
In inet_name_to_sa, made get{host,net}byname be called with
signals blocked in OSF1.
--- John Gibson, Sep 12 1996
Removed use of sys*iomessage.
--- John Gibson, Dec 1 1995
Also changed do_connect to treat EADDRINUSE as equivalent to EALREADY
--- John Gibson, Nov 20 1995
Fixed do_connect to deal with EALREADY and EISCONN errors after
an interrupted connect attempt.
--- John Gibson, Mar 25 1995
Changed ulong types to uint
--- John Gibson, Dec 14 1994
Fix to inet_name_to_sa
*/