1 /* Jim - A small embeddable Tcl interpreter
3 * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
4 * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
5 * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
6 * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
7 * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
8 * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
9 * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials
20 * provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * The views and conclusions contained in the software and documentation
36 * are those of the authors and should not be interpreted as representing
37 * official policies, either expressed or implied, of the Jim Tcl Project.
40 #include "jimautoconf.h"
56 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <netinet/tcp.h>
60 #include <arpa/inet.h>
70 #include <openssl/ssl.h>
71 #include <openssl/err.h>
78 #include "jim-eventloop.h"
79 #include "jim-subcmd.h"
81 #define AIO_CMD_LEN 32 /* e.g. aio.handleXXXXXX */
82 #define AIO_BUF_LEN 256 /* Can keep this small and rely on stdio buffering */
91 #define AIO_KEEPOPEN 1
102 #define JimCheckStreamError(interp, af) af->fops->error(af)
104 #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
107 struct sockaddr_in sin
;
109 struct sockaddr_in6 sin6
;
113 #ifndef HAVE_INET_NTOP
114 const char *inet_ntop(int af
, const void *src
, char *dst
, int size
)
119 snprintf(dst
, size
, "%s", inet_ntoa(((struct sockaddr_in
*)src
)->sin_addr
));
123 #endif /* JIM_BOOTSTRAP */
128 int (*writer
)(struct AioFile
*af
, const char *buf
, int len
);
129 int (*reader
)(struct AioFile
*af
, char *buf
, int len
);
130 const char *(*getline
)(struct AioFile
*af
, char *buf
, int len
);
131 int (*error
)(const struct AioFile
*af
);
132 const char *(*strerror
)(struct AioFile
*af
);
133 int (*verify
)(struct AioFile
*af
);
136 typedef struct AioFile
141 int openFlags
; /* AIO_KEEPOPEN? keep FILE* */
148 const JimAioFopsType
*fops
;
151 static int stdio_writer(struct AioFile
*af
, const char *buf
, int len
)
153 return fwrite(buf
, 1, len
, af
->fp
);
156 static int stdio_reader(struct AioFile
*af
, char *buf
, int len
)
158 return fread(buf
, 1, len
, af
->fp
);
161 static const char *stdio_getline(struct AioFile
*af
, char *buf
, int len
)
163 return fgets(buf
, len
, af
->fp
);
166 static int stdio_error(const AioFile
*af
)
168 if (!ferror(af
->fp
)) {
172 /* EAGAIN and similar are not error conditions. Just treat them like eof */
173 if (feof(af
->fp
) || errno
== EAGAIN
|| errno
== EINTR
) {
177 if (errno
== ECONNRESET
) {
182 if (errno
== ECONNABORTED
) {
189 static const char *stdio_strerror(struct AioFile
*af
)
191 return strerror(errno
);
194 static const JimAioFopsType stdio_fops
= {
203 #if defined(JIM_SSL) && !defined(JIM_BOOTSTRAP)
205 static SSL_CTX
*JimAioSslCtx(Jim_Interp
*interp
);
207 static int ssl_writer(struct AioFile
*af
, const char *buf
, int len
)
209 return SSL_write(af
->ssl
, buf
, len
);
212 static int ssl_reader(struct AioFile
*af
, char *buf
, int len
)
214 return SSL_read(af
->ssl
, buf
, len
);
217 static const char *ssl_getline(struct AioFile
*af
, char *buf
, int len
)
220 for (i
= 0; i
< len
+ 1; i
++) {
221 if (SSL_read(af
->ssl
, &buf
[i
], 1) != 1) {
227 if (buf
[i
] == '\n') {
235 static int ssl_error(const struct AioFile
*af
)
237 if (ERR_peek_error() == 0) {
244 static const char *ssl_strerror(struct AioFile
*af
)
246 int err
= ERR_get_error();
249 return ERR_error_string(err
, NULL
);
252 /* should not happen */
253 return "unknown SSL error";
256 static int ssl_verify(struct AioFile
*af
)
260 cert
= SSL_get_peer_certificate(af
->ssl
);
266 if (SSL_get_verify_result(af
->ssl
) == X509_V_OK
) {
273 static const JimAioFopsType ssl_fops
= {
281 #endif /* JIM_BOOTSTRAP */
283 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
284 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
285 const char *hdlfmt
, int family
, const char *mode
);
287 #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
288 static int JimParseIPv6Address(Jim_Interp
*interp
, const char *hostport
, union sockaddr_any
*sa
, int *salen
)
292 * An IPv6 addr/port looks like:
295 * [fe80::223:6cff:fe95:bdc0%en1]:2000
299 * Note that the "any" address is ::, which is the same as when no address is specified.
307 stport
= strrchr(hostport
, ':');
309 /* No : so, the whole thing is the port */
312 sthost
= Jim_StrDup(hostport
);
318 if (*hostport
== '[') {
319 /* This is a numeric ipv6 address */
320 char *pt
= strchr(++hostport
, ']');
322 sthost
= Jim_StrDupLen(hostport
, pt
- hostport
);
327 sthost
= Jim_StrDupLen(hostport
, stport
- hostport
- 1);
330 memset(&req
, '\0', sizeof(req
));
331 req
.ai_family
= PF_INET6
;
333 if (getaddrinfo(sthost
, NULL
, &req
, &ai
)) {
334 Jim_SetResultFormatted(interp
, "Not a valid address: %s", hostport
);
338 memcpy(&sa
->sin
, ai
->ai_addr
, ai
->ai_addrlen
);
339 *salen
= ai
->ai_addrlen
;
341 sa
->sin
.sin_port
= htons(atoi(stport
));
349 Jim_SetResultString(interp
, "ipv6 not supported", -1);
354 static int JimParseIpAddress(Jim_Interp
*interp
, const char *hostport
, union sockaddr_any
*sa
, int *salen
)
356 /* An IPv4 addr/port looks like:
361 * If the address is missing, INADDR_ANY is used.
362 * If the port is missing, 0 is used (only useful for server sockets).
368 stport
= strrchr(hostport
, ':');
370 /* No : so, the whole thing is the port */
372 sthost
= Jim_StrDup("0.0.0.0");
375 sthost
= Jim_StrDupLen(hostport
, stport
- hostport
);
380 #ifdef HAVE_GETADDRINFO
383 memset(&req
, '\0', sizeof(req
));
384 req
.ai_family
= PF_INET
;
386 if (getaddrinfo(sthost
, NULL
, &req
, &ai
)) {
390 memcpy(&sa
->sin
, ai
->ai_addr
, ai
->ai_addrlen
);
391 *salen
= ai
->ai_addrlen
;
399 if ((he
= gethostbyname(sthost
)) != NULL
) {
400 if (he
->h_length
== sizeof(sa
->sin
.sin_addr
)) {
401 *salen
= sizeof(sa
->sin
);
402 sa
->sin
.sin_family
= he
->h_addrtype
;
403 memcpy(&sa
->sin
.sin_addr
, he
->h_addr
, he
->h_length
); /* set address */
409 sa
->sin
.sin_port
= htons(atoi(stport
));
414 Jim_SetResultFormatted(interp
, "Not a valid address: %s", hostport
);
421 static int JimParseDomainAddress(Jim_Interp
*interp
, const char *path
, struct sockaddr_un
*sa
)
423 sa
->sun_family
= PF_UNIX
;
424 snprintf(sa
->sun_path
, sizeof(sa
->sun_path
), "%s", path
);
431 * Format that address in 'sa' as a string and store in variable 'varObjPtr'
433 static int JimFormatIpAddress(Jim_Interp
*interp
, Jim_Obj
*varObjPtr
, const union sockaddr_any
*sa
)
435 /* INET6_ADDRSTRLEN is 46. Add some for [] and port */
439 if (sa
->sa
.sa_family
== PF_INET6
) {
441 /* Allow 9 for []:65535\0 */
442 inet_ntop(sa
->sa
.sa_family
, &sa
->sin6
.sin6_addr
, addrbuf
+ 1, sizeof(addrbuf
) - 9);
443 snprintf(addrbuf
+ strlen(addrbuf
), 8, "]:%d", ntohs(sa
->sin
.sin_port
));
447 if (sa
->sa
.sa_family
== PF_INET
) {
448 /* Allow 7 for :65535\0 */
449 inet_ntop(sa
->sa
.sa_family
, &sa
->sin
.sin_addr
, addrbuf
, sizeof(addrbuf
) - 7);
450 snprintf(addrbuf
+ strlen(addrbuf
), 7, ":%d", ntohs(sa
->sin
.sin_port
));
453 /* recvfrom still works on unix domain sockets, etc */
457 return Jim_SetVariable(interp
, varObjPtr
, Jim_NewStringObj(interp
, addrbuf
, -1));
460 #endif /* JIM_BOOTSTRAP */
462 static const char *JimAioErrorString(AioFile
*af
)
465 return af
->fops
->strerror(af
);
467 return strerror(errno
);
470 static void JimAioSetError(Jim_Interp
*interp
, Jim_Obj
*name
)
472 AioFile
*af
= Jim_CmdPrivData(interp
);
475 Jim_SetResultFormatted(interp
, "%#s: %s", name
, JimAioErrorString(af
));
478 Jim_SetResultString(interp
, JimAioErrorString(af
), -1);
482 static void JimAioDelProc(Jim_Interp
*interp
, void *privData
)
484 AioFile
*af
= privData
;
488 Jim_DecrRefCount(interp
, af
->filename
);
490 #ifdef jim_ext_eventloop
491 /* remove all existing EventHandlers */
492 Jim_DeleteFileHandler(interp
, af
->fd
, JIM_EVENT_READABLE
| JIM_EVENT_WRITABLE
| JIM_EVENT_EXCEPTION
);
496 if (af
->ssl
!= NULL
) {
500 if (!(af
->openFlags
& AIO_KEEPOPEN
)) {
507 static int aio_cmd_read(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
509 AioFile
*af
= Jim_CmdPrivData(interp
);
510 char buf
[AIO_BUF_LEN
];
513 jim_wide neededLen
= -1; /* -1 is "read as much as possible" */
515 if (argc
&& Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
521 if (Jim_GetWide(interp
, argv
[0], &neededLen
) != JIM_OK
)
524 Jim_SetResultString(interp
, "invalid parameter: negative len", -1);
531 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
532 while (neededLen
!= 0) {
536 if (neededLen
== -1) {
537 readlen
= AIO_BUF_LEN
;
540 readlen
= (neededLen
> AIO_BUF_LEN
? AIO_BUF_LEN
: neededLen
);
542 retval
= af
->fops
->reader(af
, buf
, readlen
);
544 Jim_AppendString(interp
, objPtr
, buf
, retval
);
545 if (neededLen
!= -1) {
549 if (retval
!= readlen
)
552 /* Check for error conditions */
553 if (JimCheckStreamError(interp
, af
)) {
554 Jim_FreeNewObj(interp
, objPtr
);
559 const char *s
= Jim_GetString(objPtr
, &len
);
561 if (len
> 0 && s
[len
- 1] == '\n') {
563 objPtr
->bytes
[objPtr
->length
] = '\0';
566 Jim_SetResult(interp
, objPtr
);
570 AioFile
*Jim_AioFile(Jim_Interp
*interp
, Jim_Obj
*command
)
572 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, command
, JIM_ERRMSG
);
574 /* XXX: There ought to be a supported API for this */
575 if (cmdPtr
&& !cmdPtr
->isproc
&& cmdPtr
->u
.native
.cmdProc
== JimAioSubCmdProc
) {
576 return (AioFile
*) cmdPtr
->u
.native
.privData
;
578 Jim_SetResultFormatted(interp
, "Not a filehandle: \"%#s\"", command
);
582 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
)
586 af
= Jim_AioFile(interp
, command
);
594 static int aio_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
596 AioFile
*af
= Jim_CmdPrivData(interp
);
598 jim_wide maxlen
= JIM_WIDE_MAX
;
599 AioFile
*outf
= Jim_AioFile(interp
, argv
[0]);
606 if (Jim_GetWide(interp
, argv
[1], &maxlen
) != JIM_OK
) {
611 while (count
< maxlen
) {
614 if (af
->fops
->reader(af
, &ch
, 1) != 1) {
617 if (outf
->fops
->writer(outf
, &ch
, 1) != 1) {
623 if (JimCheckStreamError(interp
, af
) || JimCheckStreamError(interp
, outf
)) {
627 Jim_SetResultInt(interp
, count
);
632 static int aio_cmd_gets(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
634 AioFile
*af
= Jim_CmdPrivData(interp
);
635 char buf
[AIO_BUF_LEN
];
641 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
643 buf
[AIO_BUF_LEN
- 1] = '_';
645 if (af
->fops
->getline(af
, buf
, AIO_BUF_LEN
) == NULL
)
648 if (buf
[AIO_BUF_LEN
- 1] == '\0' && buf
[AIO_BUF_LEN
- 2] != '\n') {
649 Jim_AppendString(interp
, objPtr
, buf
, AIO_BUF_LEN
- 1);
654 if (len
&& (buf
[len
- 1] == '\n')) {
659 Jim_AppendString(interp
, objPtr
, buf
, len
);
664 if (JimCheckStreamError(interp
, af
)) {
666 Jim_FreeNewObj(interp
, objPtr
);
671 if (Jim_SetVariable(interp
, argv
[0], objPtr
) != JIM_OK
) {
672 Jim_FreeNewObj(interp
, objPtr
);
676 len
= Jim_Length(objPtr
);
678 if (len
== 0 && feof(af
->fp
)) {
679 /* On EOF returns -1 if varName was specified */
682 Jim_SetResultInt(interp
, len
);
685 Jim_SetResult(interp
, objPtr
);
690 static int aio_cmd_puts(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
692 AioFile
*af
= Jim_CmdPrivData(interp
);
698 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
707 wdata
= Jim_GetString(strObj
, &wlen
);
708 if (af
->fops
->writer(af
, wdata
, wlen
) == wlen
) {
709 if (argc
== 2 || af
->fops
->writer(af
, "\n", 1) == 1) {
713 JimAioSetError(interp
, af
->filename
);
717 static int aio_cmd_isatty(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
720 AioFile
*af
= Jim_CmdPrivData(interp
);
721 Jim_SetResultInt(interp
, isatty(fileno(af
->fp
)));
723 Jim_SetResultInt(interp
, 0);
729 #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
730 static int aio_cmd_recvfrom(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
732 AioFile
*af
= Jim_CmdPrivData(interp
);
734 union sockaddr_any sa
;
736 socklen_t salen
= sizeof(sa
);
739 if (Jim_GetLong(interp
, argv
[0], &len
) != JIM_OK
) {
743 buf
= Jim_Alloc(len
+ 1);
745 rlen
= recvfrom(fileno(af
->fp
), buf
, len
, 0, &sa
.sa
, &salen
);
748 JimAioSetError(interp
, NULL
);
752 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, rlen
));
755 return JimFormatIpAddress(interp
, argv
[1], &sa
);
762 static int aio_cmd_sendto(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
764 AioFile
*af
= Jim_CmdPrivData(interp
);
768 union sockaddr_any sa
;
769 const char *addr
= Jim_String(argv
[1]);
772 if (IPV6
&& af
->addr_family
== PF_INET6
) {
773 if (JimParseIPv6Address(interp
, addr
, &sa
, &salen
) != JIM_OK
) {
777 else if (JimParseIpAddress(interp
, addr
, &sa
, &salen
) != JIM_OK
) {
780 wdata
= Jim_GetString(argv
[0], &wlen
);
782 /* Note that we don't validate the socket type. Rely on sendto() failing if appropriate */
783 len
= sendto(fileno(af
->fp
), wdata
, wlen
, 0, &sa
.sa
, salen
);
785 JimAioSetError(interp
, NULL
);
788 Jim_SetResultInt(interp
, len
);
792 static int aio_cmd_accept(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
794 AioFile
*af
= Jim_CmdPrivData(interp
);
796 union sockaddr_any sa
;
797 socklen_t addrlen
= sizeof(sa
);
799 sock
= accept(af
->fd
, &sa
.sa
, &addrlen
);
801 JimAioSetError(interp
, NULL
);
806 if (JimFormatIpAddress(interp
, argv
[0], &sa
) != JIM_OK
) {
811 /* Create the file command */
812 return JimMakeChannel(interp
, NULL
, sock
, Jim_NewStringObj(interp
, "accept", -1),
813 "aio.sockstream%ld", af
->addr_family
, "r+") ? JIM_OK
: JIM_ERR
;
816 static int aio_cmd_listen(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
818 AioFile
*af
= Jim_CmdPrivData(interp
);
821 if (Jim_GetLong(interp
, argv
[0], &backlog
) != JIM_OK
) {
825 if (listen(af
->fd
, backlog
)) {
826 JimAioSetError(interp
, NULL
);
832 #endif /* JIM_BOOTSTRAP */
834 static int aio_cmd_flush(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
836 AioFile
*af
= Jim_CmdPrivData(interp
);
838 if (fflush(af
->fp
) == EOF
) {
839 JimAioSetError(interp
, af
->filename
);
845 static int aio_cmd_eof(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
847 AioFile
*af
= Jim_CmdPrivData(interp
);
849 Jim_SetResultInt(interp
, feof(af
->fp
));
853 static int aio_cmd_close(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
856 #if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN)
857 static const char * const options
[] = { "r", "w", NULL
};
858 enum { OPT_R
, OPT_W
, };
860 AioFile
*af
= Jim_CmdPrivData(interp
);
862 if (Jim_GetEnum(interp
, argv
[2], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
865 if (shutdown(af
->fd
, option
== OPT_R
? SHUT_RD
: SHUT_WR
) == 0) {
868 JimAioSetError(interp
, NULL
);
870 Jim_SetResultString(interp
, "async close not supported", -1);
875 return Jim_DeleteCommand(interp
, Jim_String(argv
[0]));
878 static int aio_cmd_seek(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
880 AioFile
*af
= Jim_CmdPrivData(interp
);
885 if (Jim_CompareStringImmediate(interp
, argv
[1], "start"))
887 else if (Jim_CompareStringImmediate(interp
, argv
[1], "current"))
889 else if (Jim_CompareStringImmediate(interp
, argv
[1], "end"))
895 if (Jim_GetWide(interp
, argv
[0], &offset
) != JIM_OK
) {
898 if (fseeko(af
->fp
, offset
, orig
) == -1) {
899 JimAioSetError(interp
, af
->filename
);
905 static int aio_cmd_tell(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
907 AioFile
*af
= Jim_CmdPrivData(interp
);
909 Jim_SetResultInt(interp
, ftello(af
->fp
));
913 static int aio_cmd_filename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
915 AioFile
*af
= Jim_CmdPrivData(interp
);
917 Jim_SetResult(interp
, af
->filename
);
922 static int aio_cmd_ndelay(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
924 AioFile
*af
= Jim_CmdPrivData(interp
);
926 int fmode
= fcntl(af
->fd
, F_GETFL
);
931 if (Jim_GetLong(interp
, argv
[0], &nb
) != JIM_OK
) {
940 (void)fcntl(af
->fd
, F_SETFL
, fmode
);
942 Jim_SetResultInt(interp
, (fmode
& O_NONBLOCK
) ? 1 : 0);
947 #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
948 #define SOCKOPT_BOOL 0
949 #define SOCKOPT_INT 1
950 #define SOCKOPT_TIMEVAL 2 /* not currently supported */
952 static const struct sockopt_def
{
956 int type
; /* SOCKOPT_xxx */
960 { "broadcast", SOL_SOCKET
, SO_BROADCAST
},
963 { "debug", SOL_SOCKET
, SO_DEBUG
},
966 { "keepalive", SOL_SOCKET
, SO_KEEPALIVE
},
969 { "nosigpipe", SOL_SOCKET
, SO_NOSIGPIPE
},
972 { "oobinline", SOL_SOCKET
, SO_OOBINLINE
},
975 { "sndbuf", SOL_SOCKET
, SO_SNDBUF
, SOCKOPT_INT
},
978 { "rcvbuf", SOL_SOCKET
, SO_RCVBUF
, SOCKOPT_INT
},
980 #if 0 && defined(SO_SNDTIMEO)
981 { "sndtimeo", SOL_SOCKET
, SO_SNDTIMEO
, SOCKOPT_TIMEVAL
},
983 #if 0 && defined(SO_RCVTIMEO)
984 { "rcvtimeo", SOL_SOCKET
, SO_RCVTIMEO
, SOCKOPT_TIMEVAL
},
989 { "tcp_nodelay", IPPROTO_TCP
, TCP_NODELAY
},
994 static int aio_cmd_sockopt(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
996 AioFile
*af
= Jim_CmdPrivData(interp
);
1000 Jim_Obj
*dictObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
1001 for (i
= 0; i
< sizeof(sockopts
) / sizeof(*sockopts
); i
++) {
1003 socklen_t len
= sizeof(value
);
1004 if (getsockopt(af
->fd
, sockopts
[i
].level
, sockopts
[i
].opt
, (void *)&value
, &len
) == 0) {
1005 if (sockopts
[i
].type
== SOCKOPT_BOOL
) {
1008 Jim_ListAppendElement(interp
, dictObjPtr
, Jim_NewStringObj(interp
, sockopts
[i
].name
, -1));
1009 Jim_ListAppendElement(interp
, dictObjPtr
, Jim_NewIntObj(interp
, value
));
1012 Jim_SetResult(interp
, dictObjPtr
);
1020 for (i
= 0; i
< sizeof(sockopts
) / sizeof(*sockopts
); i
++) {
1021 if (strcmp(Jim_String(argv
[0]), sockopts
[i
].name
) == 0) {
1023 if (sockopts
[i
].type
== SOCKOPT_BOOL
) {
1024 if (Jim_GetBoolean(interp
, argv
[1], &on
) != JIM_OK
) {
1030 if (Jim_GetLong(interp
, argv
[1], &longval
) != JIM_OK
) {
1035 if (setsockopt(af
->fd
, sockopts
[i
].level
, sockopts
[i
].opt
, (void *)&on
, sizeof(on
)) < 0) {
1036 Jim_SetResultFormatted(interp
, "Failed to set %#s: %s", argv
[0], strerror(errno
));
1043 Jim_SetResultFormatted(interp
, "Unknown sockopt %#s", argv
[0]);
1049 static int aio_cmd_sync(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1051 AioFile
*af
= Jim_CmdPrivData(interp
);
1059 static int aio_cmd_buffering(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1061 AioFile
*af
= Jim_CmdPrivData(interp
);
1063 static const char * const options
[] = {
1077 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
1082 setvbuf(af
->fp
, NULL
, _IONBF
, 0);
1085 setvbuf(af
->fp
, NULL
, _IOLBF
, BUFSIZ
);
1088 setvbuf(af
->fp
, NULL
, _IOFBF
, BUFSIZ
);
1094 #ifdef jim_ext_eventloop
1095 static void JimAioFileEventFinalizer(Jim_Interp
*interp
, void *clientData
)
1097 Jim_Obj
**objPtrPtr
= clientData
;
1099 Jim_DecrRefCount(interp
, *objPtrPtr
);
1103 static int JimAioFileEventHandler(Jim_Interp
*interp
, void *clientData
, int mask
)
1105 Jim_Obj
**objPtrPtr
= clientData
;
1107 return Jim_EvalObjBackground(interp
, *objPtrPtr
);
1110 static int aio_eventinfo(Jim_Interp
*interp
, AioFile
* af
, unsigned mask
, Jim_Obj
**scriptHandlerObj
,
1111 int argc
, Jim_Obj
* const *argv
)
1114 /* Return current script */
1115 if (*scriptHandlerObj
) {
1116 Jim_SetResult(interp
, *scriptHandlerObj
);
1121 if (*scriptHandlerObj
) {
1122 /* Delete old handler */
1123 Jim_DeleteFileHandler(interp
, af
->fd
, mask
);
1126 /* Now possibly add the new script(s) */
1127 if (Jim_Length(argv
[0]) == 0) {
1128 /* Empty script, so done */
1132 /* A new script to add */
1133 Jim_IncrRefCount(argv
[0]);
1134 *scriptHandlerObj
= argv
[0];
1136 Jim_CreateFileHandler(interp
, af
->fd
, mask
,
1137 JimAioFileEventHandler
, scriptHandlerObj
, JimAioFileEventFinalizer
);
1142 static int aio_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1144 AioFile
*af
= Jim_CmdPrivData(interp
);
1146 return aio_eventinfo(interp
, af
, JIM_EVENT_READABLE
, &af
->rEvent
, argc
, argv
);
1149 static int aio_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1151 AioFile
*af
= Jim_CmdPrivData(interp
);
1153 return aio_eventinfo(interp
, af
, JIM_EVENT_WRITABLE
, &af
->wEvent
, argc
, argv
);
1156 static int aio_cmd_onexception(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1158 AioFile
*af
= Jim_CmdPrivData(interp
);
1160 return aio_eventinfo(interp
, af
, JIM_EVENT_EXCEPTION
, &af
->eEvent
, argc
, argv
);
1164 #if defined(JIM_SSL) && !defined(JIM_BOOTSTRAP)
1165 static int aio_cmd_ssl(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1167 AioFile
*af
= Jim_CmdPrivData(interp
);
1173 if (!Jim_CompareStringImmediate(interp
, argv
[2], "-server")) {
1178 else if (argc
!= 2) {
1179 Jim_WrongNumArgs(interp
, 2, argv
, "?-server cert priv?");
1183 fd
= fileno(af
->fp
);
1184 #if defined(HAVE_DUP)
1190 ssl_ctx
= JimAioSslCtx(interp
);
1191 if (ssl_ctx
== NULL
) {
1195 ssl
= SSL_new(ssl_ctx
);
1197 #if defined(HAVE_DUP)
1200 Jim_SetResultString(interp
, ERR_error_string(ERR_get_error(), NULL
), -1);
1204 SSL_set_cipher_list(ssl
, "ALL");
1206 if (SSL_set_fd(ssl
, fileno(af
->fp
)) == 0) {
1211 if (SSL_use_certificate_file(ssl
, Jim_String(argv
[3]), SSL_FILETYPE_PEM
) != 1) {
1215 if (SSL_use_PrivateKey_file(ssl
, Jim_String(argv
[4]), SSL_FILETYPE_PEM
) != 1) {
1219 if (SSL_accept(ssl
) != 1) {
1224 if (SSL_connect(ssl
) != 1) {
1229 af
= JimMakeChannel(interp
, NULL
, fd
, NULL
, "aio.sslstream%ld", af
->addr_family
, "r+");
1235 af
->fops
= &ssl_fops
;
1240 #if defined(HAVE_DUP)
1244 Jim_SetResultString(interp
, ERR_error_string(ERR_get_error(), NULL
), -1);
1248 static int aio_cmd_verify(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1250 AioFile
*af
= Jim_CmdPrivData(interp
);
1253 if (!af
->fops
->verify
) {
1257 ret
= af
->fops
->verify(af
);
1258 if (ret
!= JIM_OK
) {
1259 if (JimCheckStreamError(interp
, af
)) {
1260 JimAioSetError(interp
, af
->filename
);
1262 Jim_SetResultString(interp
, "failed to verify the connection authenticity", -1);
1267 #endif /* JIM_BOOTSTRAP */
1269 #if defined(HAVE_STRUCT_FLOCK) && !defined(JIM_BOOTSTRAP)
1270 static int aio_cmd_lock(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1272 AioFile
*af
= Jim_CmdPrivData(interp
);
1277 fl
.l_type
= F_WRLCK
;
1278 fl
.l_whence
= SEEK_SET
;
1280 switch (fcntl(af
->fd
, F_SETLK
, &fl
))
1283 Jim_SetResultInt(interp
, 1);
1286 if (errno
== EACCES
|| errno
== EAGAIN
)
1287 Jim_SetResultInt(interp
, 0);
1290 Jim_SetResultFormatted(interp
, "lock failed: %s",
1296 Jim_SetResultInt(interp
, 0);
1303 static int aio_cmd_unlock(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1305 AioFile
*af
= Jim_CmdPrivData(interp
);
1309 fl
.l_type
= F_UNLCK
;
1310 fl
.l_whence
= SEEK_SET
;
1312 Jim_SetResultInt(interp
, fcntl(af
->fd
, F_SETLK
, &fl
) == 0);
1315 #endif /* JIM_BOOTSTRAP */
1317 #if defined(HAVE_TERMIOS_H) && !defined(JIM_BOOTSTRAP)
1318 static int aio_cmd_tty(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1320 AioFile
*af
= Jim_CmdPrivData(interp
);
1321 Jim_Obj
*dictObjPtr
;
1325 /* get the current settings as a dictionary */
1326 dictObjPtr
= Jim_GetTtySettings(interp
, af
->fd
);
1327 if (dictObjPtr
== NULL
) {
1328 JimAioSetError(interp
, NULL
);
1331 Jim_SetResult(interp
, dictObjPtr
);
1336 /* Convert name value arguments to a dictionary */
1337 dictObjPtr
= Jim_NewListObj(interp
, argv
, argc
);
1340 /* The settings are already given as a list */
1341 dictObjPtr
= argv
[0];
1343 Jim_IncrRefCount(dictObjPtr
);
1345 if (Jim_ListLength(interp
, dictObjPtr
) % 2) {
1346 /* Must be a valid dictionary */
1347 Jim_DecrRefCount(interp
, dictObjPtr
);
1351 ret
= Jim_SetTtySettings(interp
, af
->fd
, dictObjPtr
);
1353 JimAioSetError(interp
, NULL
);
1356 Jim_DecrRefCount(interp
, dictObjPtr
);
1360 #endif /* JIM_BOOTSTRAP */
1362 static const jim_subcmd_type aio_command_table
[] = {
1364 "?-nonewline? ?len?",
1368 /* Description: Read and return bytes from the stream. To eof if no len. */
1375 /* Description: Copy up to 'size' bytes to the given filehandle, or to eof if no size. */
1382 /* Description: Read one line and return it or store it in the var */
1389 /* Description: Write the string, with newline unless -nonewline */
1396 /* Description: Is the file descriptor a tty? */
1398 #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
1404 /* Description: Receive up to 'len' bytes on the socket. Sets 'addrvar' with receive address, if set */
1411 /* Description: Send 'str' to the given address (dgram only) */
1418 /* Description: Server socket only: Accept a connection and return stream */
1425 /* Description: Set the listen backlog for server socket */
1427 #endif /* JIM_BOOTSTRAP */
1433 /* Description: Flush the stream */
1440 /* Description: Returns 1 if stream is at eof */
1447 JIM_MODFLAG_FULLARGV
,
1448 /* Description: Closes the stream. */
1451 "offset ?start|current|end",
1455 /* Description: Seeks in the stream (default 'current') */
1462 /* Description: Returns the current seek position */
1469 /* Description: Returns the original filename */
1477 /* Description: Set O_NDELAY (if arg). Returns current/new setting. */
1480 #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
1486 /* Description: Return a dictionary of sockopts, or set the value of a sockopt */
1495 /* Description: Flush and fsync() the stream */
1503 /* Description: Sets buffering */
1505 #ifdef jim_ext_eventloop
1507 "?readable-script?",
1511 /* Description: Returns script, or invoke readable-script when readable, {} to remove */
1514 "?writable-script?",
1518 /* Description: Returns script, or invoke writable-script when writable, {} to remove */
1521 "?exception-script?",
1522 aio_cmd_onexception
,
1525 /* Description: Returns script, or invoke exception-script when oob data, {} to remove */
1528 #if defined(JIM_SSL) && !defined(JIM_BOOTSTRAP)
1530 "?-server cert priv?",
1534 JIM_MODFLAG_FULLARGV
1535 /* Description: Wraps a stream socket with SSL/TLS and returns a new channel */
1542 /* Description: Verifies the certificate of a SSL/TLS channel */
1544 #endif /* JIM_BOOTSTRAP */
1545 #if defined(HAVE_STRUCT_FLOCK) && !defined(JIM_BOOTSTRAP)
1551 /* Description: Attempt to get a lock. */
1558 /* Description: Relase a lock. */
1560 #endif /* JIM_BOOTSTRAP */
1561 #if defined(HAVE_TERMIOS_H) && !defined(JIM_BOOTSTRAP)
1563 "?baud rate? ?data bits? ?stop bits? ?parity even|odd|none? ?handshake xonxoff|rtscts|none? ?input raw|cooked? ?output raw|cooked? ?vmin n? ?vtime n?",
1567 /* Description: Get or set tty settings - valid only on a tty */
1569 #endif /* JIM_BOOTSTRAP */
1573 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1575 return Jim_CallSubCmd(interp
, Jim_ParseSubCmd(interp
, aio_command_table
, argc
, argv
), argc
, argv
);
1578 static int JimAioOpenCommand(Jim_Interp
*interp
, int argc
,
1579 Jim_Obj
*const *argv
)
1583 if (argc
!= 2 && argc
!= 3) {
1584 Jim_WrongNumArgs(interp
, 1, argv
, "filename ?mode?");
1588 mode
= (argc
== 3) ? Jim_String(argv
[2]) : "r";
1590 #ifdef jim_ext_tclcompat
1592 const char *filename
= Jim_String(argv
[1]);
1594 /* If the filename starts with '|', use popen instead */
1595 if (*filename
== '|') {
1596 Jim_Obj
*evalObj
[3];
1598 evalObj
[0] = Jim_NewStringObj(interp
, "::popen", -1);
1599 evalObj
[1] = Jim_NewStringObj(interp
, filename
+ 1, -1);
1600 evalObj
[2] = Jim_NewStringObj(interp
, mode
, -1);
1602 return Jim_EvalObjVector(interp
, 3, evalObj
);
1606 return JimMakeChannel(interp
, NULL
, -1, argv
[1], "aio.handle%ld", 0, mode
) ? JIM_OK
: JIM_ERR
;
1609 #if defined(JIM_SSL) && !defined(JIM_BOOTSTRAP)
1610 static void JimAioSslContextDelProc(struct Jim_Interp
*interp
, void *privData
)
1612 SSL_CTX_free((SSL_CTX
*)privData
);
1616 static SSL_CTX
*JimAioSslCtx(Jim_Interp
*interp
)
1618 SSL_CTX
*ssl_ctx
= (SSL_CTX
*)Jim_GetAssocData(interp
, "ssl_ctx");
1619 if (ssl_ctx
== NULL
) {
1620 SSL_load_error_strings();
1622 ssl_ctx
= SSL_CTX_new(TLSv1_2_method());
1623 if (ssl_ctx
&& SSL_CTX_set_default_verify_paths(ssl_ctx
)) {
1624 SSL_CTX_set_verify(ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
1625 Jim_SetAssocData(interp
, "ssl_ctx", JimAioSslContextDelProc
, ssl_ctx
);
1627 Jim_SetResultString(interp
, ERR_error_string(ERR_get_error(), NULL
), -1);
1632 #endif /* JIM_BOOTSTRAP */
1635 * Creates a channel for fh/fd/filename.
1637 * If fh is not NULL, uses that as the channel (and sets AIO_KEEPOPEN).
1638 * Otherwise, if fd is >= 0, uses that as the channel.
1639 * Otherwise opens 'filename' with mode 'mode'.
1641 * hdlfmt is a sprintf format for the filehandle. Anything with %ld at the end will do.
1642 * mode is used for open or fdopen.
1644 * Creates the command and sets the name as the current result.
1645 * Returns the AioFile pointer on sucess or NULL on failure.
1647 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
1648 const char *hdlfmt
, int family
, const char *mode
)
1651 char buf
[AIO_CMD_LEN
];
1654 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
1657 openFlags
= AIO_KEEPOPEN
;
1660 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
1662 filename
= Jim_NewStringObj(interp
, buf
, -1);
1665 Jim_IncrRefCount(filename
);
1668 #if !defined(JIM_ANSIC)
1670 fh
= fdopen(fd
, mode
);
1674 fh
= fopen(Jim_String(filename
), mode
);
1677 JimAioSetError(interp
, filename
);
1678 #if !defined(JIM_ANSIC)
1683 Jim_DecrRefCount(interp
, filename
);
1688 /* Create the file command */
1689 af
= Jim_Alloc(sizeof(*af
));
1690 memset(af
, 0, sizeof(*af
));
1692 af
->fd
= fileno(fh
);
1693 af
->filename
= filename
;
1695 if ((openFlags
& AIO_KEEPOPEN
) == 0) {
1696 (void)fcntl(af
->fd
, F_SETFD
, FD_CLOEXEC
);
1699 af
->openFlags
= openFlags
;
1700 af
->addr_family
= family
;
1701 af
->fops
= &stdio_fops
;
1704 Jim_CreateCommand(interp
, buf
, JimAioSubCmdProc
, af
, JimAioDelProc
);
1706 /* Note that the command must use the global namespace, even if
1707 * the current namespace is something different
1709 Jim_SetResult(interp
, Jim_MakeGlobalNamespaceName(interp
, Jim_NewStringObj(interp
, buf
, -1)));
1714 #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H))
1716 * Create a pair of channels. e.g. from pipe() or socketpair()
1718 static int JimMakeChannelPair(Jim_Interp
*interp
, int p
[2], Jim_Obj
*filename
,
1719 const char *hdlfmt
, int family
, const char *mode
[2])
1721 if (JimMakeChannel(interp
, NULL
, p
[0], filename
, hdlfmt
, family
, mode
[0])) {
1722 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
1723 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
1725 if (JimMakeChannel(interp
, NULL
, p
[1], filename
, hdlfmt
, family
, mode
[1])) {
1726 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
1727 Jim_SetResult(interp
, objPtr
);
1732 /* Can only be here if fdopen() failed */
1735 JimAioSetError(interp
, NULL
);
1740 #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
1742 static int JimAioSockCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1744 const char *hdlfmt
= "aio.unknown%ld";
1745 const char *socktypes
[] = {
1765 SOCK_STREAM_SOCKETPAIR
,
1769 const char *hostportarg
= NULL
;
1772 const char *mode
= "r+";
1773 int family
= PF_INET
;
1774 Jim_Obj
*argv0
= argv
[0];
1777 if (argc
> 1 && Jim_CompareStringImmediate(interp
, argv
[1], "-ipv6")) {
1779 Jim_SetResultString(interp
, "ipv6 not supported", -1);
1790 Jim_WrongNumArgs(interp
, 1, &argv0
, "?-ipv6? type ?address?");
1794 if (Jim_GetEnum(interp
, argv
[1], socktypes
, &socktype
, "socket type", JIM_ERRMSG
) != JIM_OK
)
1795 return Jim_CheckShowCommands(interp
, argv
[1], socktypes
);
1797 Jim_SetEmptyResult(interp
);
1799 hdlfmt
= "aio.sock%ld";
1802 hostportarg
= Jim_String(argv
[2]);
1806 case SOCK_DGRAM_CLIENT
:
1808 /* No address, so an unconnected dgram socket */
1809 sock
= socket(family
, SOCK_DGRAM
, 0);
1811 JimAioSetError(interp
, NULL
);
1817 case SOCK_STREAM_CLIENT
:
1819 union sockaddr_any sa
;
1827 if (JimParseIPv6Address(interp
, hostportarg
, &sa
, &salen
) != JIM_OK
) {
1831 else if (JimParseIpAddress(interp
, hostportarg
, &sa
, &salen
) != JIM_OK
) {
1834 sock
= socket(family
, (socktype
== SOCK_DGRAM_CLIENT
) ? SOCK_DGRAM
: SOCK_STREAM
, 0);
1836 JimAioSetError(interp
, NULL
);
1839 res
= connect(sock
, &sa
.sa
, salen
);
1841 JimAioSetError(interp
, argv
[2]);
1848 case SOCK_STREAM_SERVER
:
1849 case SOCK_DGRAM_SERVER
:
1851 union sockaddr_any sa
;
1859 if (JimParseIPv6Address(interp
, hostportarg
, &sa
, &salen
) != JIM_OK
) {
1863 else if (JimParseIpAddress(interp
, hostportarg
, &sa
, &salen
) != JIM_OK
) {
1866 sock
= socket(family
, (socktype
== SOCK_DGRAM_SERVER
) ? SOCK_DGRAM
: SOCK_STREAM
, 0);
1868 JimAioSetError(interp
, NULL
);
1872 /* Enable address reuse */
1873 setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&on
, sizeof(on
));
1875 res
= bind(sock
, &sa
.sa
, salen
);
1877 JimAioSetError(interp
, argv
[2]);
1881 if (socktype
== SOCK_STREAM_SERVER
) {
1882 res
= listen(sock
, 5);
1884 JimAioSetError(interp
, NULL
);
1889 hdlfmt
= "aio.socksrv%ld";
1893 #ifdef HAVE_SYS_UN_H
1896 struct sockaddr_un sa
;
1899 if (argc
!= 3 || ipv6
) {
1903 if (JimParseDomainAddress(interp
, hostportarg
, &sa
) != JIM_OK
) {
1904 JimAioSetError(interp
, argv
[2]);
1908 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1910 JimAioSetError(interp
, NULL
);
1913 len
= strlen(sa
.sun_path
) + 1 + sizeof(sa
.sun_family
);
1914 res
= connect(sock
, (struct sockaddr
*)&sa
, len
);
1916 JimAioSetError(interp
, argv
[2]);
1920 hdlfmt
= "aio.sockunix%ld";
1924 case SOCK_UNIX_SERVER
:
1926 struct sockaddr_un sa
;
1929 if (argc
!= 3 || ipv6
) {
1933 if (JimParseDomainAddress(interp
, hostportarg
, &sa
) != JIM_OK
) {
1934 JimAioSetError(interp
, argv
[2]);
1938 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1940 JimAioSetError(interp
, NULL
);
1943 len
= strlen(sa
.sun_path
) + 1 + sizeof(sa
.sun_family
);
1944 res
= bind(sock
, (struct sockaddr
*)&sa
, len
);
1946 JimAioSetError(interp
, argv
[2]);
1950 res
= listen(sock
, 5);
1952 JimAioSetError(interp
, NULL
);
1956 hdlfmt
= "aio.sockunixsrv%ld";
1961 #if defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H)
1962 case SOCK_STREAM_SOCKETPAIR
:
1965 static const char *mode
[2] = { "r+", "r+" };
1967 if (argc
!= 2 || ipv6
) {
1971 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, p
) < 0) {
1972 JimAioSetError(interp
, NULL
);
1975 return JimMakeChannelPair(interp
, p
, argv
[1], "aio.sockpair%ld", PF_UNIX
, mode
);
1980 #if defined(HAVE_PIPE)
1981 case SOCK_STREAM_PIPE
:
1984 static const char *mode
[2] = { "r", "w" };
1986 if (argc
!= 2 || ipv6
) {
1991 JimAioSetError(interp
, NULL
);
1995 return JimMakeChannelPair(interp
, p
, argv
[1], "aio.pipe%ld", 0, mode
);
2001 Jim_SetResultString(interp
, "Unsupported socket type", -1);
2005 return JimMakeChannel(interp
, NULL
, sock
, argv
[1], hdlfmt
, family
, mode
) ? JIM_OK
: JIM_ERR
;
2007 #endif /* JIM_BOOTSTRAP */
2010 * Returns the file descriptor of a writable, newly created temp file
2013 * On success, leaves the filename in the interpreter result, otherwise
2014 * leaves an error message.
2016 int Jim_MakeTempFile(Jim_Interp
*interp
, const char *filename_template
)
2021 Jim_Obj
*filenameObj
;
2023 if (filename_template
== NULL
) {
2024 const char *tmpdir
= getenv("TMPDIR");
2025 if (tmpdir
== NULL
|| *tmpdir
== '\0' || access(tmpdir
, W_OK
) != 0) {
2028 filenameObj
= Jim_NewStringObj(interp
, tmpdir
, -1);
2029 if (tmpdir
[0] && tmpdir
[strlen(tmpdir
) - 1] != '/') {
2030 Jim_AppendString(interp
, filenameObj
, "/", 1);
2032 Jim_AppendString(interp
, filenameObj
, "tcl.tmp.XXXXXX", -1);
2035 filenameObj
= Jim_NewStringObj(interp
, filename_template
, -1);
2038 /* Update the template name directly with the filename */
2039 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
2040 fd
= mkstemp(filenameObj
->bytes
);
2043 Jim_IncrRefCount(filenameObj
);
2044 Jim_SetResultFormatted(interp
, "%#s: %s", filenameObj
, strerror(errno
));
2048 Jim_SetResult(interp
, filenameObj
);
2051 Jim_SetResultString(interp
, "platform has no tempfile support", -1);
2056 #if defined(JIM_SSL) && !defined(JIM_BOOTSTRAP)
2057 static int JimAioLoadSSLCertsCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2062 Jim_WrongNumArgs(interp
, 1, argv
, "dir");
2066 ssl_ctx
= JimAioSslCtx(interp
);
2070 if (SSL_CTX_load_verify_locations(ssl_ctx
, NULL
, Jim_String(argv
[1])) == 1) {
2073 Jim_SetResultString(interp
, ERR_error_string(ERR_get_error(), NULL
), -1);
2076 #endif /* JIM_BOOTSTRAP */
2078 int Jim_aioInit(Jim_Interp
*interp
)
2080 if (Jim_PackageProvide(interp
, "aio", "1.0", JIM_ERRMSG
))
2083 #if defined(JIM_SSL)
2084 Jim_CreateCommand(interp
, "load_ssl_certs", JimAioLoadSSLCertsCommand
, NULL
, NULL
);
2087 Jim_CreateCommand(interp
, "open", JimAioOpenCommand
, NULL
, NULL
);
2089 Jim_CreateCommand(interp
, "socket", JimAioSockCommand
, NULL
, NULL
);
2092 /* Create filehandles for stdin, stdout and stderr */
2093 JimMakeChannel(interp
, stdin
, -1, NULL
, "stdin", 0, "r");
2094 JimMakeChannel(interp
, stdout
, -1, NULL
, "stdout", 0, "w");
2095 JimMakeChannel(interp
, stderr
, -1, NULL
, "stderr", 0, "w");