32 #ifndef _QORE_QORE_SOCKET_PRIVATE_H
33 #define _QORE_QORE_SOCKET_PRIVATE_H
35 #include "qore/intern/SSLSocketHelper.h"
37 #include "qore/intern/QC_Queue.h"
46 #include <openssl/ssl.h>
47 #include <openssl/err.h>
51 #elif defined HAVE_SYS_SELECT_H
52 #include <sys/select.h>
53 #elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
56 #error no async socket I/O APIs available
59 #ifndef DEFAULT_SOCKET_BUFSIZE
60 #define DEFAULT_SOCKET_BUFSIZE 4096
63 #ifndef QORE_MAX_HEADER_SIZE
64 #define QORE_MAX_HEADER_SIZE 16384
67 #define CHF_HTTP11 (1 << 0)
68 #define CHF_PROCESS (1 << 1)
69 #define CHF_REQUEST (1 << 2)
71 #ifndef DEFAULT_SOCKET_MIN_THRESHOLD_BYTES
72 #define DEFAULT_SOCKET_MIN_THRESHOLD_BYTES 1024
75 static constexpr
int SOCK_POLLIN = (1 << 0);
76 static constexpr
int SOCK_POLLOUT = (1 << 1);
77 static constexpr
int SOCK_POLLERR = (1 << 2);
79 DLLLOCAL
void concat_target(
QoreString& str,
const struct sockaddr *addr,
const char* type =
"target");
81 DLLLOCAL
int sock_get_raw_error();
82 DLLLOCAL
int sock_get_error();
83 DLLLOCAL
void qore_socket_error(
ExceptionSink* xsink,
const char* err,
const char* cdesc,
const char* mname = 0,
const char* host = 0,
const char* svc = 0,
const struct sockaddr *addr = 0);
84 DLLLOCAL
void qore_socket_error_intern(
int rc,
ExceptionSink* xsink,
const char* err,
const char* cdesc,
const char* mname = 0,
const char* host = 0,
const char* svc = 0,
const struct sockaddr *addr = 0);
85 DLLLOCAL
void se_in_op(
const char* cname,
const char* meth,
ExceptionSink* xsink);
86 DLLLOCAL
void se_in_op_thread(
const char* cname,
const char* meth,
ExceptionSink* xsink);
87 DLLLOCAL
void se_not_open(
const char* cname,
const char* meth,
ExceptionSink* xsink,
const char* extra =
nullptr);
88 DLLLOCAL
void se_timeout(
const char* cname,
const char* meth,
int timeout_ms,
ExceptionSink* xsink);
89 DLLLOCAL
void se_closed(
const char* cname,
const char* mname,
ExceptionSink* xsink);
92 #define GETSOCKOPT_ARG_4 char*
93 #define SETSOCKOPT_ARG_4 const char*
94 #define SHUTDOWN_ARG SD_BOTH
95 #define QORE_INVALID_SOCKET ((int)INVALID_SOCKET)
96 #define QORE_SOCKET_ERROR SOCKET_ERROR
97 DLLLOCAL
int check_windows_rc(
int rc);
100 #define ECONNRESET WSAECONNRESET
105 #define GETSOCKOPT_ARG_4 void*
106 #define SETSOCKOPT_ARG_4 void*
107 #define SHUTDOWN_ARG SHUT_RDWR
108 #define QORE_INVALID_SOCKET -1
109 #define QORE_SOCKET_ERROR -1
112 template <
typename T>
113 class PrivateDataListHolder {
115 DLLLOCAL PrivateDataListHolder(
ExceptionSink* xsink) : xsink(xsink) {
118 DLLLOCAL ~PrivateDataListHolder() {
119 for (
auto& i : pd_vec)
127 pd_vec.push_back(pd);
132 typedef std::vector<T*> pd_vec_t;
137 hashdecl qore_socketsource_private {
141 DLLLOCAL qore_socketsource_private() : address(0), hostname(0) {
144 DLLLOCAL ~qore_socketsource_private() {
145 if (address) address->deref();
146 if (hostname) hostname->deref();
154 DLLLOCAL
void setAddress(
const char* addr) {
159 DLLLOCAL
void setHostName(
const char* host) {
166 o->
setValue(
"source", address, xsink);
171 o->
setValue(
"source_host", hostname, xsink);
177 class OptionalNonBlockingHelper {
179 qore_socket_private& sock;
183 DLLLOCAL OptionalNonBlockingHelper(qore_socket_private& s,
bool n_set,
ExceptionSink* xs);
184 DLLLOCAL ~OptionalNonBlockingHelper();
187 class PrivateQoreSocketTimeoutBase {
189 hashdecl qore_socket_private* sock;
193 DLLLOCAL PrivateQoreSocketTimeoutBase(qore_socket_private* s) : sock(s), start(sock ? q_clock_getmicros() : 0) {
197 class PrivateQoreSocketTimeoutHelper :
public PrivateQoreSocketTimeoutBase {
201 DLLLOCAL PrivateQoreSocketTimeoutHelper(qore_socket_private* s,
const char* op);
202 DLLLOCAL ~PrivateQoreSocketTimeoutHelper();
205 class PrivateQoreSocketThroughputHelper :
public PrivateQoreSocketTimeoutBase {
209 DLLLOCAL PrivateQoreSocketThroughputHelper(qore_socket_private* s,
bool snd);
210 DLLLOCAL ~PrivateQoreSocketThroughputHelper();
212 DLLLOCAL
void finalize(
int64 bytes);
215 hashdecl qore_socket_private;
217 hashdecl qore_socket_op_helper {
219 qore_socket_private* s;
222 DLLLOCAL qore_socket_op_helper(qore_socket_private* sock);
223 DLLLOCAL ~qore_socket_op_helper();
226 class SSLSocketHelperHelper {
228 qore_socket_private* s;
229 SSLSocketHelper* ssl;
230 bool context_saved =
false;
233 DLLLOCAL SSLSocketHelperHelper(qore_socket_private* sock,
bool set_thread_context =
false);
235 DLLLOCAL ~SSLSocketHelperHelper();
237 DLLLOCAL
void error();
240 hashdecl qore_socket_private {
241 friend class PrivateQoreSocketTimeoutHelper;
242 friend class PrivateQoreSocketThroughputHelper;
245 static thread_local qore_socket_private* current_socket;
247 int sock, sfamily, port, stype, sprot;
250 int64 connection_id = 0;
254 std::string socketname;
256 std::string client_target;
257 SSLSocketHelper* ssl =
nullptr;
258 Queue* event_queue =
nullptr,
259 * warn_queue =
nullptr;
262 std::string assume_http_encoding =
"ISO-8859-1";
265 char rbuf[DEFAULT_SOCKET_BUFSIZE];
271 int64 tl_warning_us = 0;
272 double tp_warning_bs = 0;
273 int64 tp_bytes_sent = 0,
285 http_exp_chunked_body =
false,
286 ssl_accept_all_certs =
false,
287 ssl_capture_remote_cert =
false,
290 ssl_verify_mode = SSL_VERIFY_NONE;
298 DLLLOCAL qore_socket_private(
int n_sock = QORE_INVALID_SOCKET,
int n_sfamily = AF_UNSPEC,
int n_stype = SOCK_STREAM,
int n_prot = 0,
const QoreEncoding* n_enc =
QCS_DEFAULT) :
299 sock(n_sock), sfamily(n_sfamily), port(-1), stype(n_stype), sprot(n_prot), enc(n_enc) {
302 DLLLOCAL ~qore_socket_private() {
306 assert(!event_queue);
310 DLLLOCAL
bool isOpen() {
311 return sock != QORE_INVALID_SOCKET;
314 DLLLOCAL
int close() {
315 int rc = close_internal();
318 if (http_exp_chunked_body)
319 http_exp_chunked_body =
false;
327 DLLLOCAL
int close_and_reset() {
328 assert(sock != QORE_INVALID_SOCKET);
332 rc = ::closesocket(sock);
337 if (!rc || sock_get_error() != EINTR)
341 sock = QORE_INVALID_SOCKET;
351 client_target.clear();
355 DLLLOCAL
int close_internal() {
358 ssl_err_str->deref();
359 ssl_err_str =
nullptr;
362 remote_cert->
deref(
nullptr);
363 remote_cert =
nullptr;
373 if (!socketname.empty()) {
375 unlink(socketname.c_str());
383 return close_and_reset();
389 DLLLOCAL
void setAssumedEncoding(
const char* str) {
390 assume_http_encoding = str;
393 DLLLOCAL
const char* getAssumedEncoding()
const {
394 return assume_http_encoding.c_str();
397 DLLLOCAL
int getSendTimeout()
const {
400 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
403 int size =
sizeof(
hashdecl timeval);
405 socklen_t size =
sizeof(
hashdecl timeval);
408 if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
411 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
414 DLLLOCAL
int getRecvTimeout()
const {
417 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
420 int size =
sizeof(
hashdecl timeval);
422 socklen_t size =
sizeof(
hashdecl timeval);
425 if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
428 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
431 DLLLOCAL
int getPort() {
433 if (sock == QORE_INVALID_SOCKET || (sfamily != AF_INET && sfamily != AF_INET6) || port > 0)
437 hashdecl sockaddr_storage addr;
438 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
440 int size =
sizeof addr;
442 socklen_t size =
sizeof addr;
445 if (getsockname(sock, (
struct sockaddr *)&addr, (socklen_t *)&size) < 0)
448 port = q_get_port_from_addr((
const struct sockaddr *)&addr);
453 switch (v.getType()) {
458 hdr.
sprintf(
"%s: " QLLD
"\r\n", key, v.getAsBigInt());
462 size_t offset = hdr.
size();
463 hdr.
sprintf(
"%f\r\n", v.getAsFloat());
467 q_fix_decimal(&hdr, offset);
476 hdr.
sprintf(
"%s: %d\r\n", key, (
int)v.getAsBool());
484 DLLLOCAL
static void do_headers(
QoreString& hdr,
const QoreHashNode* headers,
size_t size,
bool addsize =
true) {
492 const char* key = hi.getKey();
493 if (addsize && !strcasecmp(key,
"transfer-encoding"))
495 if ((addsize || size) && !strcasecmp(key,
"content-length")) {
502 do_header(key, hdr, li.getValue());
504 do_header(key, hdr, v);
508 if (size || addsize) {
509 hdr.
sprintf(
"Content-Length: " QSD
"\r\n", size);
515 DLLLOCAL
int listen(
int backlog = 20) {
516 if (sock == QORE_INVALID_SOCKET)
521 if (::listen(sock, backlog)) {
528 return ::listen(sock, backlog);
532 DLLLOCAL
int accept_intern(
ExceptionSink* xsink,
struct sockaddr *addr, socklen_t *size,
int timeout_ms = -1) {
536 if (timeout_ms >= 0 && !isDataAvailable(timeout_ms,
"accept", xsink)) {
543 int rc = ::accept(sock, addr, size);
544 if (rc != QORE_INVALID_SOCKET)
548 if (sock_get_error() == EINTR)
551 qore_socket_error(xsink,
"SOCKET-ACCEPT-ERROR",
"error in accept()", 0, 0, 0, addr);
559 if (sock == QORE_INVALID_SOCKET) {
560 xsink->
raiseException(
"SOCKET-NOT-OPEN",
"socket must be opened, bound, and in a listening state before new connections can be accepted");
565 se_in_op(
"Socket",
"accept", xsink);
568 se_in_op_thread(
"Socket",
"accept", xsink);
569 return QSE_IN_OP_THREAD;
573 if (sfamily == AF_UNIX) {
575 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"UNIX sockets are not available under Windows");
578 hashdecl sockaddr_un addr_un;
580 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
583 int size =
sizeof(
hashdecl sockaddr_un);
585 socklen_t size =
sizeof(
hashdecl sockaddr_un);
587 rc = accept_intern(xsink, (
struct sockaddr *)&addr_un, (socklen_t *)&size, timeout_ms);
590 if (rc >= 0 && source) {
592 addr->
sprintf(
"UNIX socket: %s", socketname.c_str());
593 source->priv->setAddress(addr);
594 source->priv->setHostName(
"localhost");
597 }
else if (sfamily == AF_INET || sfamily == AF_INET6) {
598 hashdecl sockaddr_storage addr_in;
599 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
602 int size =
sizeof(addr_in);
604 socklen_t size =
sizeof(addr_in);
607 rc = accept_intern(xsink, (
struct sockaddr *)&addr_in, (socklen_t *)&size, timeout_ms);
610 if (rc >= 0 && source) {
611 char host[NI_MAXHOST + 1];
612 char service[NI_MAXSERV + 1];
614 if (!getnameinfo((
struct sockaddr *)&addr_in, qore_get_in_len((
struct sockaddr *)&addr_in), host,
sizeof(host), service,
sizeof(service), NI_NUMERICSERV)) {
615 source->priv->setHostName(host);
619 char ifname[INET6_ADDRSTRLEN];
620 if (inet_ntop(addr_in.ss_family, qore_get_in_addr((
struct sockaddr *)&addr_in), ifname,
sizeof(ifname))) {
622 source->priv->setAddress(ifname);
627 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"do not know how to accept connections with address family %d", sfamily);
633 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_SOCKET)
const {
652 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
655 event_queue->deref(xsink);
656 event_queue =
nullptr;
659 warn_queue->deref(xsink);
660 warn_queue =
nullptr;
661 if (warn_callback_arg) {
662 warn_callback_arg.
discard(xsink);
663 warn_callback_arg.clear();
673 event_queue->deref(xsink);
677 event_data = with_data;
680 DLLLOCAL
void do_start_ssl_event() {
682 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_START_SSL));
686 DLLLOCAL
void do_ssl_established_event() {
691 event_queue->pushAndTakeRef(h);
695 DLLLOCAL
void do_connect_event(
int af,
const struct sockaddr* addr,
const char* target,
const char* service =
nullptr,
int prt = -1) {
704 q_af_to_hash(af, *h,
nullptr);
710 event_queue->pushAndTakeRef(h);
714 DLLLOCAL
void do_connected_event() {
716 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CONNECTED));
720 DLLLOCAL
void do_data_event_intern(
int event,
int source,
const QoreStringNode& str)
const {
721 assert(event_queue && event_data && str.
size());
724 event_queue->pushAndTakeRef(h.release());
727 DLLLOCAL
void do_data_event(
int event,
int source,
const QoreStringNode& str)
const {
728 if (event_queue && event_data && str.
size()) {
729 do_data_event_intern(event, source, str);
733 DLLLOCAL
void do_data_event(
int event,
int source,
const BinaryNode& b)
const {
734 if (event_queue && event_data && b.
size()) {
737 event_queue->pushAndTakeRef(h.release());
741 DLLLOCAL
void do_data_event(
int event,
int source,
const void* data,
size_t size)
const {
742 if (event_queue && event_data && size) {
747 event_queue->pushAndTakeRef(h.release());
751 DLLLOCAL
void do_header_event(
int event,
int source,
const QoreHashNode& hdr)
const {
752 if (event_queue && event_data && !hdr.
empty()) {
755 event_queue->pushAndTakeRef(h.release());
759 DLLLOCAL
void do_chunked_read(
int event,
size_t bytes,
size_t total_read,
int source) {
762 if (event == QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED)
767 event_queue->pushAndTakeRef(h);
771 DLLLOCAL
void do_read_http_header(
int event,
const QoreHashNode* headers,
int source) {
775 event_queue->pushAndTakeRef(h);
779 DLLLOCAL
void do_send_http_message_event(
const QoreString& str,
const QoreHashNode* headers,
int source) {
781 QoreHashNode* h = getEvent(QORE_EVENT_HTTP_SEND_MESSAGE, source);
785 event_queue->pushAndTakeRef(h);
789 DLLLOCAL
void do_close_event() {
791 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
795 DLLLOCAL
void do_read_event(
size_t bytes_read,
size_t total_read,
size_t bufsize = 0,
int source = QORE_SOURCE_SOCKET) {
798 QoreHashNode* h = getEvent(QORE_EVENT_PACKET_READ, source);
804 event_queue->pushAndTakeRef(h);
808 DLLLOCAL
void do_send_event(
int bytes_sent,
int total_sent,
int bufsize) {
815 event_queue->pushAndTakeRef(h);
819 DLLLOCAL
void do_resolve_event(
const char* host,
const char* service = 0) {
827 event_queue->pushAndTakeRef(h);
831 DLLLOCAL
void do_resolved_event(
const struct sockaddr* addr) {
834 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_RESOLVED);
840 int prt = q_get_port_from_addr(addr);
843 q_af_to_hash(addr->sa_family, *h,
nullptr);
844 event_queue->pushAndTakeRef(h);
848 DLLLOCAL
int64 getObjectIDForEvents()
const {
852 DLLLOCAL
int connectUNIX(
const char* p,
int sock_type,
int protocol,
ExceptionSink* xsink) {
855 QORE_TRACE(
"connectUNIX()");
858 xsink->
raiseException(
"SOCKET-CONNECTUNIX-ERROR",
"UNIX sockets are not available under Windows");
864 printd(5,
"qore_socket_private::connectUNIX(%s)\n", p);
866 hashdecl sockaddr_un addr;
868 addr.sun_family = AF_UNIX;
870 strncpy(addr.sun_path, p,
sizeof(addr.sun_path) - 1);
871 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
872 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_SOCKET_ERROR) {
873 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"error connecting to UNIX socket: '%s'", p);
877 do_connect_event(AF_UNIX, (sockaddr*)&addr, p);
879 if (!::connect(sock, (
const sockaddr *)&addr,
sizeof(
struct sockaddr_un)))
883 if (sock_get_error() == EINTR)
889 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, p);
895 socketname = addr.sun_path;
898 do_connected_event();
910 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
const char* cname,
const char* mname,
ExceptionSink* xsink)
const {
912 assert(read || write);
913 if (sock == QORE_INVALID_SOCKET) {
914 se_not_open(cname, mname, xsink,
"asyncIoWait");
918 return asyncIoWait(timeout_ms, read, write, xsink);
921 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
ExceptionSink* xsink)
const {
923 #if defined HAVE_POLL
924 return poll_intern(xsink, timeout_ms, read, write);
925 #elif defined HAVE_SELECT
926 return select_intern(xsink, timeout_ms, read, write);
928 #error no async socket operations supported
932 #if defined HAVE_POLL
933 DLLLOCAL
int poll_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
940 pollfd fds = {sock, arg, 0};
942 rc = ::poll(&fds, 1, timeout_ms);
943 if (rc == -1 && errno == EINTR)
948 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"poll(2) returned an error");
949 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
954 #elif defined HAVE_SELECT
955 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
956 bool aborted =
false;
957 int rc = select_intern(xsink, timeout_ms, read, write, aborted);
958 if (rc != QORE_SOCKET_ERROR && aborted)
963 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write,
bool& aborted)
const {
970 if (sock >= FD_SETSIZE) {
971 xsink->
raiseException(
"SOCKET-SELECT-ERROR",
"fd is %d which is >= %d; contact the Qore developers to implement an alternative to select() on this platform", sock, FD_SETSIZE);
986 tv.tv_sec = timeout_ms / 1000;
987 tv.tv_usec = (timeout_ms % 1000) * 1000;
989 fd_set* readfd = read ? &sfs : 0;
990 fd_set* writefd = write ? &sfs : 0;
992 rc = select(sock + 1, readfd, writefd, &err, &tv);
994 if (rc != QORE_SOCKET_ERROR) {
995 if (FD_ISSET(sock, &err))
999 if (sock_get_error() != EINTR)
1002 if (rc == QORE_SOCKET_ERROR) {
1005 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"select(2) returned an error");
1012 DLLLOCAL
bool tryReadSocketData(
const char* mname,
ExceptionSink* xsink) {
1017 return asyncIoWait(0,
true,
false,
"Socket", mname, xsink);
1021 int rc = ssl->doSSLRW(xsink, mname, rbuf, 1, 0, PEEK,
false);
1022 if (*xsink || (rc == QSE_TIMEOUT)) {
1025 return rc > 0 ? true :
false;
1028 DLLLOCAL
bool isSocketDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1029 return asyncIoWait(timeout_ms,
true,
false,
"Socket", mname, xsink);
1032 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1035 return isSocketDataAvailable(timeout_ms, mname, xsink);
1038 DLLLOCAL
bool isWriteFinished(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1039 return asyncIoWait(timeout_ms,
false,
true,
"Socket", mname, xsink);
1042 DLLLOCAL
int close_and_exit() {
1043 if (sock != QORE_INVALID_SOCKET)
1048 DLLLOCAL
int connectINETTimeout(
int timeout_ms,
const struct sockaddr* ai_addr,
size_t ai_addrlen,
ExceptionSink* xsink,
bool only_timeout) {
1050 PrivateQoreSocketTimeoutHelper toh(
this,
"connect");
1053 if (!::connect(sock, ai_addr, ai_addrlen))
1057 if (sock_get_error() != EAGAIN) {
1058 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1066 if (errno != EINPROGRESS)
1075 bool aborted =
false;
1076 int rc = select_intern(xsink, timeout_ms,
false,
true, aborted);
1082 if (rc != QORE_SOCKET_ERROR && aborted) {
1083 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1087 int rc = asyncIoWait(timeout_ms,
false,
true,
"Socket",
"connectINETTimeout", xsink);
1093 if (rc == QORE_SOCKET_ERROR && sock_get_error() != EINTR) {
1095 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in asyncIoWait() with Socket::connect() with timeout", 0, 0, 0, ai_addr);
1097 }
else if (rc > 0) {
1099 socklen_t lon =
sizeof(int);
1102 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (GETSOCKOPT_ARG_4)(&val), &lon) == QORE_SOCKET_ERROR) {
1104 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()", 0, 0, 0, ai_addr);
1113 qore_socket_error_intern(val, xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()", 0, 0, 0, ai_addr);
1121 concat_target(*(*desc), ai_addr);
1131 DLLLOCAL
int sock_errno_err(
const char* err,
const char* desc,
ExceptionSink* xsink) {
1132 sock = QORE_INVALID_SOCKET;
1133 qore_socket_error(xsink, err, desc);
1137 DLLLOCAL
int set_non_blocking(
bool non_blocking,
ExceptionSink* xsink) {
1141 if (sock == QORE_INVALID_SOCKET) {
1142 assert(!xsink || *xsink);
1147 u_long mode = non_blocking ? 1 : 0;
1148 int rc = ioctlsocket(sock, FIONBIO, &mode);
1149 if (check_windows_rc(rc))
1150 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in ioctlsocket(FIONBIO)", xsink);
1155 if ((arg = fcntl(sock, F_GETFL, 0)) < 0)
1156 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() getting socket descriptor status flag", xsink);
1163 if (fcntl(sock, F_SETFL, arg) < 0)
1164 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() setting socket descriptor status flag", xsink);
1170 DLLLOCAL
int connectINET(
const char* host,
const char* service,
int timeout_ms,
ExceptionSink* xsink,
int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0) {
1172 family = q_get_af(family);
1173 type = q_get_sock_type(type);
1175 QORE_TRACE(
"qore_socket_private::connectINET()");
1180 printd(5,
"qore_socket_private::connectINET(%s:%s, %dms)\n", host, service, timeout_ms);
1182 do_resolve_event(host, service);
1185 if (ai.
getInfo(xsink, host, service, family, 0, type, protocol))
1192 for (
struct addrinfo *p = aip; p; p = p->ai_next)
1193 do_resolved_event(p->ai_addr);
1195 int prt = q_get_port_from_addr(aip->ai_addr);
1197 for (
struct addrinfo *p = aip; p; p = p->ai_next) {
1198 if (!connectINETIntern(host, service, p->ai_family, p->ai_addr, p->ai_addrlen, p->ai_socktype, p->ai_protocol, prt, timeout_ms, xsink,
true))
1205 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1209 DLLLOCAL
int connectINETIntern(
const char* host,
const char* service,
int ai_family,
struct sockaddr* ai_addr,
size_t ai_addrlen,
int ai_socktype,
int ai_protocol,
int prt,
int timeout_ms,
ExceptionSink* xsink,
bool only_timeout =
false) {
1211 printd(5,
"qore_socket_private::connectINETIntern() host: %s service: %s family: %d timeout_ms: %d\n", host, service, ai_family, timeout_ms);
1212 if ((sock = socket(ai_family, ai_socktype, ai_protocol)) == QORE_INVALID_SOCKET) {
1213 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"cannot establish a connection to %s:%s", host, service);
1222 if (timeout_ms >= 0) {
1224 if (set_non_blocking(
true, xsink))
1225 return close_and_exit();
1227 do_connect_event(ai_family, ai_addr, host, service, prt);
1229 rc = connectINETTimeout(timeout_ms, ai_addr, ai_addrlen, xsink, only_timeout);
1233 if (set_non_blocking(
false, xsink))
1234 return close_and_exit();
1236 do_connect_event(ai_family, ai_addr, host, service, prt);
1239 rc = ::connect(sock, ai_addr, ai_addrlen);
1242 if (!rc || sock_get_error() != EINTR)
1248 if (!only_timeout || errno == ETIMEDOUT)
1249 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1251 return close_and_exit();
1254 sfamily = ai_family;
1255 stype = ai_socktype;
1256 sprot = ai_protocol;
1260 do_connected_event();
1263 client_target = host;
1267 DLLLOCAL
int upgradeClientToSSLIntern(
const char* mname,
const char* sni_target_host, X509* cert, EVP_PKEY* pkey,
int timeout_ms,
ExceptionSink* xsink) {
1269 SSLSocketHelperHelper sshh(
this,
true);
1272 do_start_ssl_event();
1274 if (!sni_target_host && !client_target.empty()) {
1275 sni_target_host = client_target.c_str();
1277 if ((rc = ssl->setClient(mname, sni_target_host, sock, cert, pkey, xsink)) || ssl->connect(mname, timeout_ms, xsink)) {
1279 return rc ? rc : -1;
1281 do_ssl_established_event();
1286 DLLLOCAL
int upgradeServerToSSLIntern(
const char* mname, X509* cert, EVP_PKEY* pkey,
int timeout_ms,
ExceptionSink* xsink) {
1289 SSLSocketHelperHelper sshh(
this,
true);
1291 do_start_ssl_event();
1292 if (ssl->setServer(mname, sock, cert, pkey, xsink) || ssl->accept(mname, timeout_ms, xsink)) {
1296 do_ssl_established_event();
1302 DLLLOCAL
int openUNIX(
int sock_type = SOCK_STREAM,
int protocol = 0) {
1303 if (sock != QORE_INVALID_SOCKET)
1306 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_INVALID_SOCKET) {
1318 DLLLOCAL
int openINET(
int family = AF_INET,
int sock_type = SOCK_STREAM,
int protocol = 0) {
1319 if (sock != QORE_INVALID_SOCKET)
1322 if ((sock = socket(family, sock_type, protocol)) == QORE_INVALID_SOCKET)
1332 DLLLOCAL
int reuse(
int opt) {
1334 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_ARG_4)&opt,
sizeof(
int));
1338 DLLLOCAL
int bindIntern(
struct sockaddr* ai_addr,
size_t ai_addrlen,
int prt,
bool reuseaddr,
ExceptionSink* xsink = 0) {
1341 if ((::bind(sock, ai_addr, ai_addrlen)) == QORE_SOCKET_ERROR) {
1343 qore_socket_error(xsink,
"SOCKET-BIND-ERROR",
"error in bind()", 0, 0, 0, ai_addr);
1353 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1355 int len = ai_addrlen;
1357 socklen_t len = ai_addrlen;
1360 if (getsockname(sock, ai_addr, &len))
1363 port = q_get_port_from_addr(ai_addr);
1369 DLLLOCAL
int bindUNIX(
ExceptionSink* xsink,
const char* name,
int socktype = SOCK_STREAM,
int protocol = 0) {
1372 xsink->
raiseException(
"SOCKET-BINDUNIX-ERROR",
"UNIX sockets are not available under Windows");
1378 if (openUNIX(socktype, protocol)) {
1379 xsink->
raiseErrnoException(
"SOCKET-BIND-ERROR", errno,
"error opening UNIX socket ('%s') for bind", name);
1383 hashdecl sockaddr_un addr;
1384 addr.sun_family = AF_UNIX;
1386 strncpy(addr.sun_path, name,
sizeof(addr.sun_path) - 1);
1387 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1389 if (bindIntern((sockaddr*)&addr,
sizeof(
struct sockaddr_un), -1,
false, xsink))
1393 socketname = addr.sun_path;
1400 DLLLOCAL
int bindINET(
ExceptionSink* xsink,
const char* name,
const char* service,
bool reuseaddr =
true,
int family = AF_UNSPEC,
int socktype = SOCK_STREAM,
int protocol = 0) {
1402 family = q_get_af(family);
1403 socktype = q_get_sock_type(socktype);
1408 do_resolve_event(name, service);
1409 if (ai.
getInfo(xsink, name, service, family, AI_PASSIVE, socktype, protocol))
1415 for (
struct addrinfo *p = aip; p; p = p->ai_next)
1416 do_resolved_event(p->ai_addr);
1419 if (openINET(aip->ai_family, aip->ai_socktype, protocol)) {
1420 qore_socket_error(xsink,
"SOCKET-BINDINET-ERROR",
"error opening socket for bind", 0, name, service);
1424 int prt = q_get_port_from_addr(aip->ai_addr);
1428 for (
struct addrinfo *p = aip; p; p = p->ai_next) {
1429 if (!bindIntern(p->ai_addr, p->ai_addrlen, prt, reuseaddr)) {
1434 en = sock_get_raw_error();
1439 qore_socket_error_intern(en, xsink,
"SOCKET-BIND-ERROR",
"error binding on socket", 0, name, service);
1446 if (sock == QORE_INVALID_SOCKET) {
1447 se_not_open(
"Socket",
"getPeerInfo", xsink);
1451 hashdecl sockaddr_storage addr;
1452 socklen_t len =
sizeof addr;
1453 if (getpeername(sock, (
struct sockaddr*)&addr, &len)) {
1454 qore_socket_error(xsink,
"SOCKET-GETPEERINFO-ERROR",
"error in getpeername()");
1458 return getAddrInfo(addr, len, host_lookup);
1464 if (sock == QORE_INVALID_SOCKET) {
1465 se_not_open(
"Socket",
"getSocketInfo", xsink);
1469 hashdecl sockaddr_storage addr;
1470 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1472 int len =
sizeof addr;
1474 socklen_t len =
sizeof addr;
1477 if (getsockname(sock, (
struct sockaddr*)&addr, &len)) {
1478 qore_socket_error(xsink,
"SOCKET-GETSOCKETINFO-ERROR",
"error in getsockname()");
1482 return getAddrInfo(addr, len, host_lookup);
1485 DLLLOCAL
QoreHashNode* getAddrInfo(
const struct sockaddr_storage& addr, socklen_t len,
bool host_lookup =
true)
const {
1488 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1490 char host[NI_MAXHOST + 1];
1492 if (!getnameinfo((
struct sockaddr*)&addr, qore_get_in_len((
struct sockaddr*)&addr), host,
sizeof(host), 0, 0, 0)) {
1500 char ifname[INET6_ADDRSTRLEN];
1501 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr*)&addr), ifname,
sizeof(ifname))) {
1508 if (addr.ss_family == AF_INET) {
1509 hashdecl sockaddr_in* s = (
hashdecl sockaddr_in*)&addr;
1510 tport = ntohs(s->sin_port);
1512 hashdecl sockaddr_in6* s = (
hashdecl sockaddr_in6*)&addr;
1513 tport = ntohs(s->sin6_port);
1519 else if (addr.ss_family == AF_UNIX) {
1520 assert(!socketname.empty());
1536 hashdecl sockaddr_storage addr;
1538 socklen_t len =
sizeof addr;
1539 if (getpeername(sock, (
struct sockaddr*)&addr, &len))
1542 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1544 char ifname[INET6_ADDRSTRLEN];
1545 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr *)&addr), ifname,
sizeof(ifname))) {
1550 char host[NI_MAXHOST + 1];
1551 if (!getnameinfo((
struct sockaddr *)&addr, qore_get_in_len((
struct sockaddr *)&addr), host,
sizeof(host), 0, 0, 0))
1555 else if (addr.ss_family == AF_UNIX) {
1557 hashdecl sockaddr_un *addr_un = (
hashdecl sockaddr_un *)&addr;
1558 astr->
sprintf(
"UNIX socket: %s", addr_un->sun_path);
1566 DLLLOCAL
qore_offset_t brecv(
ExceptionSink* xsink,
const char* meth,
char*& buf,
size_t bs,
int flags,
int timeout,
bool do_event =
true) {
1569 assert(sock != QORE_INVALID_SOCKET);
1574 buf = rbuf + bufoffset;
1592 if (timeout != -1 && !isDataAvailable(timeout, meth, xsink)) {
1595 se_timeout(
"Socket", meth, timeout, xsink);
1604 rc = ::recv(sock, rbuf, DEFAULT_SOCKET_BUFSIZE, flags);
1605 if (rc == QORE_SOCKET_ERROR) {
1610 if (errno == ECONNRESET) {
1611 se_closed(
"Socket", meth, xsink);
1615 qore_socket_error(xsink,
"SOCKET-RECV-ERROR",
"error in recv()", meth);
1624 rc = ssl->read(meth, rbuf, DEFAULT_SOCKET_BUFSIZE, timeout, xsink);
1639 do_read_event(rc, rc);
1653 bool exit_early =
false) {
1656 if (sock == QORE_INVALID_SOCKET) {
1657 se_not_open(
"Socket", meth, xsink,
"readHTTPData");
1662 PrivateQoreSocketThroughputHelper th(
this,
false);
1677 rc = brecv(xsink, meth, buf, 1, 0, timeout,
false);
1685 se_closed(
"Socket", meth, xsink);
1687 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"socket closed on remote end while reading header data after reading " QSD
" byte%s", count, count == 1 ?
"" :
"s");
1693 if (++count == QORE_MAX_HEADER_SIZE) {
1694 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"header size cannot exceed " QSD
" bytes", count);
1705 if (exit_early && hdr->
empty())
1712 }
else if (c ==
'\r') {
1727 case 0: hdr->concat(
'\r');
break;
1728 case 1: hdr->concat(
"\r\n");
break;
1729 case 2: hdr->concat(
"\r\n\r");
break;
1730 case 3: hdr->concat(
'\n');
break;
1740 th.finalize(hdr->
size());
1742 return hdr.release();
1747 if (sock == QORE_INVALID_SOCKET) {
1748 se_not_open(
"Socket",
"recv", xsink,
"recv");
1754 se_in_op(
"Socket",
"recv", xsink);
1757 se_in_op_thread(
"Socket",
"recv", xsink);
1761 PrivateQoreSocketThroughputHelper th(
this,
false);
1763 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
1770 rc = brecv(xsink,
"recv", buf, bs, 0, timeout,
false);
1773 printd(5,
"qore_socket_private::recv(" QSD
", %d) bs=" QSD
", br=" QSD
", rc=" QSD
", errno: %d (%s)\n", bufsize, timeout, bs, str->
size(), rc, errno, strerror(errno));
1781 do_read_event(rc, str->
size(), bufsize, source);
1785 if (str->
size() >= (
size_t)bufsize)
1787 if ((bufsize - str->
size()) < bs)
1788 bs = bufsize - str->
size();
1792 printd(5,
"qore_socket_private::recv() received " QSD
" byte(s), bufsize=" QSD
", strlen=" QSD
" str='%s'\n", str->
size(), bufsize, (str ? str->
strlen() : 0), str ? str->
getBuffer() :
"n/a");
1798 th.finalize(str->
size());
1805 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
1807 return str.release();
1812 if (sock == QORE_INVALID_SOCKET) {
1813 se_not_open(
"Socket",
"recv", xsink,
"recvAll");
1819 se_in_op(
"Socket",
"recv", xsink);
1822 se_in_op_thread(
"Socket",
"recv", xsink);
1826 PrivateQoreSocketThroughputHelper th(
this,
false);
1832 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
1839 do_read_event(rc, rc);
1842 if (isDataAvailable(0,
"recv", xsink)) {
1844 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
1850 th.finalize(str->
size());
1856 do_read_event(rc, str->
size());
1857 }
while (isDataAvailable(0,
"recv", xsink));
1860 th.finalize(str->
size());
1868 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
1870 return str.release();
1877 if (sock == QORE_INVALID_SOCKET) {
1878 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinary");
1884 se_in_op(
"Socket",
"recvBinary", xsink);
1887 se_in_op_thread(
"Socket",
"recvBinary", xsink);
1891 PrivateQoreSocketThroughputHelper th(
this,
false);
1893 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
1899 rc = brecv(xsink,
"recvBinary", buf, bs, 0, timeout);
1906 if (b->
size() >= (
size_t)bufsize)
1908 if ((bufsize - b->
size()) < bs)
1909 bs = bufsize - b->
size();
1913 th.finalize(b->
size());
1923 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
1925 printd(5,
"qore_socket_private::recvBinary() received " QSD
" byte(s), bufsize=" QSD
", blen=" QSD
"\n", b->
size(), bufsize, b->
size());
1931 if (sock == QORE_INVALID_SOCKET) {
1932 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinaryAll");
1938 se_in_op(
"Socket",
"recvBinary", xsink);
1941 se_in_op_thread(
"Socket",
"recvBinary", xsink);
1945 PrivateQoreSocketThroughputHelper th(
this,
false);
1952 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
1959 do_read_event(rc, rc);
1962 if (isDataAvailable(0,
"recvBinary", xsink)) {
1964 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
1969 th.finalize(b->
size());
1976 do_read_event(rc, b->
size());
1977 }
while (isDataAvailable(0,
"recvBinary", xsink));
1980 th.finalize(b->
size());
1986 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
1994 if (sock == QORE_INVALID_SOCKET) {
1995 se_not_open(
"Socket",
"recvToOutputStream", xsink);
2000 se_in_op(
"Socket",
"recvToOutputStream", xsink);
2003 se_in_op_thread(
"Socket",
"recvToOutputStream", xsink);
2007 qore_socket_op_helper oh(
this);
2011 while (size < 0 || br < size) {
2013 int bn = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - br, DEFAULT_SOCKET_BUFSIZE);
2015 qore_offset_t rc = brecv(xsink,
"recvToOutputStream", buf, bn, 0, timeout);
2024 xsink->
raiseException(
"SOCKET-RECV-ERROR",
"Unexpected end of stream");
2030 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, buf, rc);
2036 os->
write(buf, rc, xsink);
2055 do_data_event(QORE_EVENT_HTTP_HEADERS_READ, source, **hdr);
2056 return hdr.release();
2060 qore_offset_t& rc,
int source,
const char* headers_raw_key =
"headers-raw") {
2068 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"remote closed the connection while reading the HTTP header");
2073 const char* buf = hdr->c_str();
2076 if ((p = (
char*)strstr(buf,
"\r\n"))) {
2079 }
else if ((p = (
char*)strchr(buf,
'\n'))) {
2082 }
else if ((p = (
char*)strchr(buf,
'\r'))) {
2088 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"invalid header received with embedded nulls in " \
2089 "Socket::readHTTPHeader()");
2094 if (!(t1 = (
char*)strstr(buf,
"HTTP/"))) {
2095 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"missing HTTP version string in first " \
2096 "header line in Socket::readHTTPHeader()");
2103 int flags = CHF_PROCESS;
2110 flags |= CHF_HTTP11;
2115 const char* info_key;
2117 char* t2 = (
char*)strchr(buf + 8,
' ');
2120 if (isdigit(*(t2))) {
2122 if (strlen(t2) > 4) {
2129 info_key =
"response-uri";
2131 char* t2 = (
char*)strchr(buf,
' ');
2136 t1 = strchr(t2,
' ');
2144 info_key =
"request-uri";
2145 flags |= CHF_REQUEST;
2149 if (info || (event_queue && event_data)) {
2151 if (info && event_queue && event_data) {
2154 if (event_queue && event_data) {
2155 do_data_event_intern(QORE_EVENT_SOCKET_DATA_READ, source, **status_line);
2158 info->
setKeyValue(info_key, *status_line,
nullptr);
2160 status_line.release();
2163 bool close = convertHeaderToHash(*h, p, flags, info, &http_exp_chunked_body, headers_raw_key);
2164 do_read_http_header(QORE_EVENT_HTTP_MESSAGE_RECEIVED, *h, source);
2167 if ((flags & CHF_REQUEST) && info)
2183 arg->
setKeyValue(
"send_aborted", send_aborted, xsink);
2184 args->push(arg,
nullptr);
2187 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2192 if (runCallback(xsink, cname, mname, rv, callback, l,
nullptr))
2195 switch (rv->getType()) {
2203 xsink->
raiseException(
"HTTP-TRAILER-ERROR",
"chunked callback returned type '%s'; expecting 'hash' or 'NOTHING'", rv->getTypeName());
2215 args->push(arg,
nullptr);
2218 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2236 if (sock == QORE_INVALID_SOCKET) {
2237 se_not_open(cname, mname, xsink,
"runCallback");
2238 return QSE_NOT_OPEN;
2246 assert(!aborted || !(*aborted));
2248 if (sock == QORE_INVALID_SOCKET) {
2249 se_not_open(cname, mname, xsink,
"sendHttpChunkedWithCallback");
2250 return QSE_NOT_OPEN;
2254 se_in_op(cname, mname, xsink);
2257 se_in_op_thread(cname, mname, xsink);
2261 PrivateQoreSocketThroughputHelper th(
this,
true);
2264 bool nb = (timeout_ms >= 0);
2266 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2270 qore_socket_op_helper oh(
this);
2279 bool data_available = tryReadSocketData(mname, xsink);
2281 if (data_available || *xsink) {
2283 return *xsink ? -1 : 0;
2289 rc = runCallback(xsink, cname, mname, res, send_callback, &l);
2298 const char* data_ptr =
nullptr;
2299 size_t data_size = 0;
2301 switch (res->getType()) {
2309 data_ptr = str->
c_str();
2310 data_size = str->
size();
2322 data_ptr =
static_cast<const char*
>(b->
getPtr());
2323 data_size = b->
size();
2335 const char* key = hi.getKey();
2342 do_header(key, buf, li.getValue());
2344 do_header(key, buf, v);
2355 xsink->
raiseException(
"SOCKET-CALLBACK-ERROR",
"HTTP chunked data callback returned type '%s'; expecting one of: 'string', 'binary', 'hash', 'nothing' (or 'NULL')", res->getTypeName());
2361 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2367 if (data_ptr && data_size) {
2368 rc = sendIntern(xsink, cname, mname, data_ptr, data_size, timeout_ms, total,
true);
2373 if (buf.
empty() && (!data_ptr || !data_size)) {
2374 buf.
set(
"0\r\n\r\n");
2378 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2384 switch (res->getType()) {
2387 if (!str->
empty()) {
2388 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *str);
2396 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *b);
2403 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, source, *h);
2411 if (aborted && *xsink) {
2412 bool data_available = tryReadSocketData(mname, xsink);
2414 if (data_available) {
2416 return *xsink ? -1 : 0;
2425 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2431 return rc < 0 || sock == QORE_INVALID_SOCKET ? -1 : 0;
2434 DLLLOCAL
int sendIntern(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
int timeout_ms,
int64& total,
bool stream =
false) {
2440 bool nb = (timeout_ms >= 0);
2445 rc = ssl->write(mname, buf + bs, size - bs, timeout_ms, xsink);
2448 rc = ::send(sock, buf + bs, size - bs, 0);
2455 if (nb && (errno == EAGAIN
2457 || errno == EWOULDBLOCK
2460 if (!isWriteFinished(timeout_ms, mname, xsink)) {
2463 se_timeout(
"Socket", mname, timeout_ms, xsink);
2469 if (errno != EINTR) {
2471 xsink->
raiseErrnoException(
"SOCKET-SEND-ERROR", errno,
"error while executing %s::%s()", cname, mname);
2475 if (!stream && errno == EPIPE)
2479 if (!stream && errno == ECONNRESET)
2490 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2495 do_send_event(rc, bs, size);
2506 DLLLOCAL
int send(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
int timeout_ms = -1,
int source = QORE_SOURCE_SOCKET) {
2508 if (sock == QORE_INVALID_SOCKET) {
2509 se_not_open(cname, mname, xsink,
"send");
2511 return QSE_NOT_OPEN;
2515 se_in_op(cname, mname, xsink);
2518 se_in_op_thread(cname, mname, xsink);
2525 PrivateQoreSocketThroughputHelper th(
this,
true);
2528 bool nb = (timeout_ms >= 0);
2530 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2535 qore_offset_t rc = sendIntern(xsink, cname, mname, buf, size, timeout_ms, total);
2538 if (rc > 0 && source > 0) {
2539 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, buf, size);
2542 return rc < 0 || sock == QORE_INVALID_SOCKET ? rc : 0;
2546 if (sock == QORE_INVALID_SOCKET) {
2547 se_not_open(
"Socket",
"sendFromInputStream", xsink);
2552 se_in_op(
"Socket",
"sendFromInputStream", xsink);
2555 se_in_op_thread(
"Socket",
"sendFromInputStream", xsink);
2559 qore_socket_op_helper oh(
this);
2561 PrivateQoreSocketThroughputHelper th(
this,
true);
2564 bool nb = (timeout >= 0);
2566 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2570 char buf[DEFAULT_SOCKET_BUFSIZE];
2573 while (size < 0 || sent < size) {
2574 int64 toRead = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - sent, DEFAULT_SOCKET_BUFSIZE);
2578 r = is->
read(buf, toRead, xsink);
2587 xsink->
raiseException(
"SOCKET-SEND-ERROR",
"Unexpected end of stream");
2593 qore_offset_t rc = sendIntern(xsink,
"Socket",
"sendFromInputStream", buf, r, timeout, total);
2597 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, QORE_SOURCE_SOCKET, buf, r);
2604 if (sock == QORE_INVALID_SOCKET) {
2605 se_not_open(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2610 se_in_op(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2613 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2617 qore_socket_op_helper oh(
this);
2619 PrivateQoreSocketThroughputHelper th(
this,
true);
2622 bool nb = (timeout >= 0);
2624 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2630 buf->preallocate(max_chunk_size);
2636 r = is->
read((
void*)buf->getPtr(),
sizeof(max_chunk_size), xsink);
2643 str.
sprintf(
"%x\r\n", (
int)r);
2644 int rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2648 bool trailers =
false;
2652 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", (
const char*)buf->getPtr(), r, timeout, total,
true);
2655 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, QORE_SOURCE_SOCKET, buf->getPtr(), r);
2656 }
else if (trailer_callback) {
2660 if (runTrailerCallback(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", *trailer_callback, l, h))
2664 do_headers(str, *h, 0,
false);
2666 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2670 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, **h);
2678 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2692 if (sock == QORE_INVALID_SOCKET) {
2693 se_not_open(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2698 se_in_op(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2701 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2711 const char* key = hi.getKey();
2716 do_header(key, buf, li.getValue());
2719 do_header(key, buf, v);
2724 sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyTrailer", buf.
getBuffer(), buf.
size(), timeout, total,
true);
2726 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, *headers);
2731 const char* method,
const char* path,
const char* http_version,
const QoreHashNode* headers,
2739 hdr.sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
2746 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
2747 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
2759 hdr.sprintf(
"HTTP/%s %03d %s", http_version, code, desc);
2767 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
2768 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
2777 assert(!(data && send_callback));
2778 assert(!(data && input_stream));
2779 assert(!(send_callback && input_stream));
2782 do_send_http_message_event(hdr, headers, source);
2787 do_headers(hdr, headers, size && data ? size : 0);
2793 if ((rc = send(xsink, cname, mname, hdr.
c_str(), hdr.
size(), timeout_ms, -1)))
2798 int rc = send(xsink, cname, mname, (
char*)data, size, timeout_ms, -1);
2801 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, *body);
2803 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, data, size);
2807 }
else if (send_callback) {
2809 assert(!aborted || !(*aborted));
2810 return sendHttpChunkedWithCallback(xsink, cname, mname, *send_callback, *l, source, timeout_ms, aborted);
2811 }
else if (input_stream) {
2813 sendHttpChunkedBodyFromInputStream(input_stream, max_chunk_size, timeout_ms, xsink, l, trailer_callback);
2814 return *xsink ? -1 : 0;
2823 if (sock == QORE_INVALID_SOCKET) {
2824 se_not_open(cname,
"readHTTPChunkedBodyBinary", xsink);
2829 se_in_op(cname,
"readHTTPChunkedBodyBinary", xsink);
2832 se_in_op_thread(cname,
"readHTTPChunkedBodyBinary", xsink);
2837 if (http_exp_chunked_body)
2838 http_exp_chunked_body =
false;
2840 qore_socket_op_helper oh(
this);
2853 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 1, 0, timeout,
false);
2857 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
2864 if (!state && c ==
'\r')
2866 else if (state && c ==
'\n')
2880 char* p = (
char*)strchr(str.
getBuffer(),
';');
2883 long size = strtol(str.
c_str(), 0, 16);
2884 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
size(), source);
2890 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
2897 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
2901 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, bs, 0, timeout,
false);
2906 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
2911 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, buf, (
size_t)rc);
2915 os->
write(buf, rc, xsink);
2937 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 2 - br, 0, timeout,
false);
2941 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
2948 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
2950 if (recv_callback && !os) {
2951 if (runDataCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, *b,
true))
2967 if (!recv_callback && !os) {
2975 return recv_callback ? 0 : h.release();
2977 if (recv_callback) {
2980 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
2981 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
2984 if (recv_callback) {
2985 runHeaderCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, h->
empty() ?
nullptr : *h,
2986 info.release(),
false, obj);
2997 if (sock == QORE_INVALID_SOCKET) {
2998 se_not_open(cname,
"readHTTPChunkedBody", xsink);
3003 se_in_op(cname,
"readHTTPChunkedBody", xsink);
3006 se_in_op_thread(cname,
"readHTTPChunkedBody", xsink);
3011 if (http_exp_chunked_body)
3012 http_exp_chunked_body =
false;
3014 qore_socket_op_helper oh(
this);
3027 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 1, 0, timeout,
false);
3031 se_closed(cname,
"readHTTPChunkedBody", xsink);
3038 if (!state && c ==
'\r')
3040 else if (state && c ==
'\n')
3054 char* p = (
char*)strchr(str.
getBuffer(),
';');
3058 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
strlen(), source);
3064 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3074 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3079 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, bs, 0, timeout,
false);
3083 se_closed(cname,
"readHTTPChunkedBody", xsink);
3089 buf->concat(tbuf, rc);
3091 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, tbuf, (
size_t)rc);
3107 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 2 - br, 0, timeout,
false);
3111 se_closed(cname,
"readHTTPChunkedBody", xsink);
3118 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3120 if (recv_callback) {
3121 if (runDataCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, *buf,
true))
3134 if (!recv_callback) {
3142 return recv_callback ? 0 : h.release();
3144 if (recv_callback) {
3147 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3148 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3151 if (recv_callback) {
3152 runHeaderCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, h->
empty() ?
nullptr : *h,
3153 info.release(),
false, obj);
3160 DLLLOCAL
static void do_accept_encoding(
char* t,
QoreHashNode& info) {
3169 while (*a && *a !=
';' && *a !=
',')
3173 l->push(str.release(),
nullptr);
3183 info.
setKeyValue(
"accept-encoding", l.release(), 0);
3186 DLLLOCAL
bool do_accept_charset(
char* t,
QoreHashNode& info) {
3187 bool acceptcharset =
false;
3202 if (*a ==
'u' || *a ==
'U') {
3204 if (*a ==
't' || *a ==
'T') {
3206 if (*a ==
'f' || *a ==
'F') {
3218 }
else if (*a ==
',') {
3222 }
else if (*a ==
';') {
3231 acceptcharset =
true;
3235 ac->concat(t, div - t);
3240 info.
setKeyValue(
"accept-charset", ac.release(), 0);
3241 acceptcharset =
true;
3245 return acceptcharset;
3250 bool* chunked =
nullptr,
const char* headers_raw_key =
"headers-raw") {
3251 bool close = !(flags & CHF_HTTP11);
3253 const char* senc =
nullptr;
3255 bool acceptcharset =
false;
3263 std::string raw_key;
3268 if ((p = strstr(buf,
"\r\n"))) {
3271 }
else if ((p = strchr(buf,
'\n'))) {
3274 }
else if ((p = strchr(buf,
'\r'))) {
3279 char* t = strchr(buf,
':');
3284 while (t && qore_isblank(*t))
3294 if (flags & CHF_PROCESS) {
3295 if (!strcmp(buf,
"connection")) {
3296 if (flags & CHF_HTTP11) {
3297 if (strcasestr(t,
"close"))
3300 if (strcasestr(t,
"keep-alive"))
3303 }
else if (!strcmp(buf,
"content-type")) {
3304 char* a = strcasestr(t,
"charset=");
3307 char* e = strchr(a + 8,
';');
3311 cs.
concat(a + 8, e - a - 8);
3320 size_t len = cs.
size();
3330 }
while (a > t && (*a ==
' ' || *a ==
';'));
3337 ct->concat(t, a - t + 1);
3343 info->
setKeyValue(
"body-content-type", ct.release(),
nullptr);
3349 info->
setKeyValue(
"body-content-type", val->refSelf(),
nullptr);
3352 }
else if (chunked && !strcmp(buf,
"transfer-encoding") && !strcasecmp(t,
"chunked")) {
3355 if (!strcmp(buf,
"accept-charset"))
3356 acceptcharset = do_accept_charset(t, *info);
3357 else if ((flags & CHF_REQUEST) && !strcmp(buf,
"accept-encoding"))
3358 do_accept_encoding(t, *info);
3363 if (raw_hdr && val) {
3364 val_copy = val->realCopy();
3368 hash_assignment_priv ha(*h, buf);
3369 if (!(*ha).isNothing()) {
3371 if ((*ha).getType() ==
NT_LIST) {
3375 l->
push(ha.swap(l),
nullptr);
3377 l->
push(val.release(),
nullptr);
3379 ha.assign(val.release(), 0);
3383 hash_assignment_priv ha(*raw_hdr, raw_key);
3384 if (!(*ha).isNothing()) {
3386 if ((*ha).getType() ==
NT_LIST) {
3390 l->
push(ha.swap(l),
nullptr);
3392 l->
push(val_copy.release(),
nullptr);
3394 ha.assign(val_copy.release(),
nullptr);
3398 if ((flags & CHF_PROCESS)) {
3402 if (info && !acceptcharset)
3409 DLLLOCAL
int recvix(
const char* meth,
int len,
void* targ,
int timeout_ms,
ExceptionSink* xsink) {
3411 if (sock == QORE_INVALID_SOCKET) {
3412 se_not_open(
"Socket", meth, xsink,
"recvix");
3413 return QSE_NOT_OPEN;
3417 se_in_op(
"Socket", meth, xsink);
3420 se_in_op_thread(
"Socket", meth, xsink);
3424 PrivateQoreSocketThroughputHelper th(
this,
false);
3429 qore_offset_t rc = brecv(xsink, meth, buf, len - br, 0, timeout_ms);
3431 do_read_error(rc, meth, timeout_ms, xsink);
3435 memcpy(targ, buf, rc);
3443 do_data_event(QORE_EVENT_SOCKET_DATA_READ, QORE_SOURCE_SOCKET, targ, br);
3449 if (warn_callback_arg) {
3450 warn_callback_arg.
discard(xsink);
3453 warn_queue->deref(xsink);
3454 warn_queue =
nullptr;
3456 tp_warning_bs = 0.0;
3464 if (warning_ms <= 0 && warning_bs <= 0) {
3465 xsink->
raiseException(
"SOCKET-SETWARNINGQUEUE-ERROR",
"Socket::setWarningQueue() at least one of warning ms argument: " QLLD
" and warning B/s argument: " QLLD
" must be greater than zero; to clear, call Socket::clearWarningQueue() with no arguments", warning_ms, warning_bs);
3475 warn_queue->
deref(xsink);
3476 warn_callback_arg.
discard(xsink);
3479 warn_queue = qholder.release();
3480 warn_callback_arg = holder.release();
3481 tl_warning_us = (
int64)warning_ms * 1000;
3482 tp_warning_bs = warning_bs;
3483 tp_us_min = min_ms * 1000;
3486 DLLLOCAL
void getUsageInfo(
QoreHashNode& h, qore_socket_private& s)
const {
3494 h.
setKeyValue(
"bytes_sent", tp_bytes_sent + s.tp_bytes_sent, 0);
3495 h.
setKeyValue(
"bytes_recv", tp_bytes_recv + s.tp_bytes_sent, 0);
3496 h.
setKeyValue(
"us_sent", tp_us_sent + s.tp_us_sent, 0);
3497 h.
setKeyValue(
"us_recv", tp_us_recv + s.tp_us_recv, 0);
3520 DLLLOCAL
void clearStats() {
3527 DLLLOCAL
void doTimeoutWarning(
const char* op,
int64 dt) {
3529 assert(dt > tl_warning_us);
3537 if (warn_callback_arg)
3540 warn_queue->pushAndTakeRef(h);
3543 DLLLOCAL
void doThroughputWarning(
bool send,
int64 bytes,
int64 dt,
double bs) {
3545 assert(bs < tp_warning_bs);
3555 if (warn_callback_arg)
3558 warn_queue->pushAndTakeRef(h);
3561 DLLLOCAL
bool pendingHttpChunkedBody()
const {
3562 return http_exp_chunked_body && sock != QORE_INVALID_SOCKET;
3565 DLLLOCAL
void setSslVerifyMode(
int mode) {
3567 ssl_verify_mode = mode;
3569 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3572 DLLLOCAL
void acceptAllCertificates(
bool accept_all =
true) {
3573 ssl_accept_all_certs = accept_all;
3575 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3580 ssl_err_str->
concat(
"; ");
3581 ssl_err_str->
concat(err_str);
3584 ssl_err_str = err_str;
3589 sock.priv->getUsageInfo(h, *s.priv);
3592 DLLLOCAL
static qore_socket_private* get(
QoreSocket& sock) {
3596 DLLLOCAL
static const qore_socket_private* get(
const QoreSocket& sock) {
3600 DLLLOCAL
static void captureRemoteCert(X509_STORE_CTX* x509_ctx);
DLLEXPORT const QoreEncoding * QCS_DEFAULT
the default encoding for the Qore library
DLLEXPORT QoreEncodingManager QEM
the QoreEncodingManager object
#define QORE_MIN(a, b)
macro to return the minimum of 2 numbers
Definition: QoreLib.h:547
DLLEXPORT QoreStringNode * q_strerror(int errnum)
returns the error string as a QoreStringNode
static void strtolower(char *str)
convert a string to lower-case in place
Definition: QoreLib.h:268
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:57
DLLEXPORT AbstractQoreNode * refSelf() const
returns "this" with an incremented reference count
virtual DLLEXPORT AbstractQoreNode * realCopy() const =0
returns a copy of the object; the caller owns the reference count
DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count and calls derefImpl() if there_can_be_only_one is false,...
provides a safe and exception-safe way to release and re-acquire locks in Qore, only to be used on th...
Definition: QoreThreadLock.h:190
holds arbitrary binary data
Definition: BinaryNode.h:41
DLLEXPORT void append(const void *nptr, size_t size)
resizes the object and appends a copy of the data passed to the object
DLLEXPORT size_t size() const
returns the number of bytes in the object
DLLEXPORT bool empty() const
returns true if empty
DLLEXPORT void clear()
frees any managed memory and sets the size to 0
DLLEXPORT const void * getPtr() const
returns the pointer to the data
constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:563
For use on the stack only: iterates through elements of a const QoreListNode.
Definition: QoreListNode.h:563
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
DLLEXPORT AbstractQoreNode * raiseErrnoException(const char *err, int en, const char *fmt,...)
appends a Qore-language exception to the list and appends the result of strerror(errno) to the descri...
DLLEXPORT AbstractQoreNode * raiseExceptionArg(const char *err, QoreValue arg, const char *fmt,...)
appends a Qore-language exception to the list, and sets the 'arg' member (this object takes over the ...
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
Interface for private data of output streams.
Definition: OutputStream.h:44
virtual void write(const void *ptr, int64 count, ExceptionSink *xsink)=0
Writes bytes to the output stream.
provides an interface to getaddrinfo
Definition: QoreNet.h:132
DLLLOCAL hashdecl addrinfo * getAddrInfo() const
returns the hashdecl addrinfo * being managed (may by 0)
Definition: QoreNet.h:159
DLLEXPORT int getInfo(ExceptionSink *xsink, const char *node, const char *service, int family=Q_AF_UNSPEC, int flags=0, int socktype=Q_SOCK_STREAM, int protocol=0)
get address info with the given parameters, if any errors occur, a Qore-language exception is thrown
static DLLEXPORT const char * getFamilyName(int address_family)
returns the name of the address family as a string (ie AF_INET = "ipv4", etc)
static DLLEXPORT QoreStringNode * getAddressDesc(int address_family, const char *addr)
returns a descriptive string for the address family and an address string (ie AF_INET6,...
defines string encoding functions in Qore
Definition: QoreEncoding.h:83
static DLLEXPORT const QoreEncoding * findCreate(const char *name)
finds an encoding if it exists (also looks up against alias names) and creates a new one if it doesn'...
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
DLLEXPORT int setKeyValue(const char *key, QoreValue value, ExceptionSink *xsink)
sets the value of "key" to "value"
DLLEXPORT size_t size() const
returns the number of members in the hash, executes in constant time
DLLEXPORT bool empty() const
returns true if the hash has no members, false if not
DLLEXPORT QoreHashNode * hashRefSelf() const
returns "this" with an incremented reference count
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
DLLEXPORT int push(QoreValue val, ExceptionSink *xsink)
adds a value to the list
Qore's arbitrary-precision number value type, dynamically-allocated only, reference counted.
Definition: QoreNumberNode.h:51
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition: QoreObject.h:60
DLLEXPORT AbstractPrivateData * getReferencedPrivateData(qore_classid_t key, ExceptionSink *xsink) const
returns the private data corresponding to the class ID passed with an incremented reference count,...
DLLEXPORT void setValue(const char *key, QoreValue val, ExceptionSink *xsink)
sets the value of the given member to the given value
provides access to sockets using Qore data structures
Definition: QoreSocket.h:126
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
DLLEXPORT void set(const char *str, const QoreEncoding *new_qorecharset=QCS_DEFAULT)
copies the c-string passed and sets the value of the string and its encoding
DLLEXPORT size_t strlen() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT void clear()
reset string to zero length; memory is not deallocated; string encoding does not change
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
DLLEXPORT size_t size() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT char * giveBuffer()
returns the character buffer and leaves the QoreString empty, the caller owns the memory returned (mu...
DLLEXPORT void trim(const char *chars=0)
remove leading and trailing whitespace or other characters
DLLEXPORT bool empty() const
returns true if the string is empty, false if not
DLLEXPORT const char * c_str() const
returns the string's buffer; this data should not be changed
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
DLLLOCAL T * release()
releases the pointer to the caller
Definition: ReferenceHolder.h:83
base class for resolved call references
Definition: CallReferenceNode.h:109
virtual DLLLOCAL QoreValue execValue(const QoreListNode *args, ExceptionSink *xsink) const =0
pure virtual function for executing the function reference
a helper class for getting socket origination information
Definition: QoreSocket.h:73
holds an object and dereferences it in the destructor
Definition: QoreValue.h:476
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
intptr_t qore_offset_t
used for offsets that could be negative
Definition: common.h:76
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260
const qore_type_t NT_BOOLEAN
type value for bools (QoreValue only)
Definition: node_types.h:47
const qore_type_t NT_NUMBER
type value for QoreNumberNode
Definition: node_types.h:53
const qore_type_t NT_BINARY
type value for BinaryNode
Definition: node_types.h:49
const qore_type_t NT_LIST
type value for QoreListNode
Definition: node_types.h:50
const qore_type_t NT_NULL
type value for QoreNullNode
Definition: node_types.h:48
const qore_type_t NT_INT
type value for integers (QoreValue only)
Definition: node_types.h:43
const qore_type_t NT_STRING
type value for QoreStringNode
Definition: node_types.h:45
const qore_type_t NT_FLOAT
type value for floating-point values (QoreValue only)
Definition: node_types.h:44
const qore_type_t NT_HASH
type value for QoreHashNode
Definition: node_types.h:51
const qore_type_t NT_NOTHING
type value for QoreNothingNode
Definition: node_types.h:42
DLLEXPORT int q_gettid() noexcept
returns the current TID number
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:275
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values
DLLEXPORT QoreValue refSelf() const
references the contained value if type == QV_Node, returns itself