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 DLLLOCAL
void concat_target(
QoreString& str,
const struct sockaddr *addr,
const char* type =
"target");
77 DLLLOCAL
int sock_get_raw_error();
78 DLLLOCAL
int sock_get_error();
79 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);
80 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);
81 DLLLOCAL
void se_in_op(
const char* cname,
const char* meth,
ExceptionSink* xsink);
82 DLLLOCAL
void se_in_op_thread(
const char* cname,
const char* meth,
ExceptionSink* xsink);
83 DLLLOCAL
void se_not_open(
const char* cname,
const char* meth,
ExceptionSink* xsink);
84 DLLLOCAL
void se_timeout(
const char* cname,
const char* meth,
int timeout_ms,
ExceptionSink* xsink);
85 DLLLOCAL
void se_closed(
const char* cname,
const char* mname,
ExceptionSink* xsink);
88 #define GETSOCKOPT_ARG_4 char* 89 #define SETSOCKOPT_ARG_4 const char* 90 #define SHUTDOWN_ARG SD_BOTH 91 #define QORE_INVALID_SOCKET ((int)INVALID_SOCKET) 92 #define QORE_SOCKET_ERROR SOCKET_ERROR 93 DLLLOCAL
int check_windows_rc(
int rc);
96 #define ECONNRESET WSAECONNRESET 101 #define GETSOCKOPT_ARG_4 void* 102 #define SETSOCKOPT_ARG_4 void* 103 #define SHUTDOWN_ARG SHUT_RDWR 104 #define QORE_INVALID_SOCKET -1 105 #define QORE_SOCKET_ERROR -1 108 hashdecl qore_socketsource_private {
112 DLLLOCAL qore_socketsource_private() : address(0), hostname(0) {
115 DLLLOCAL ~qore_socketsource_private() {
116 if (address) address->deref();
117 if (hostname) hostname->deref();
125 DLLLOCAL
void setAddress(
const char* addr) {
130 DLLLOCAL
void setHostName(
const char* host) {
137 o->
setValue(
"source", address, xsink);
142 o->
setValue(
"source_host", hostname, xsink);
148 class OptionalNonBlockingHelper {
150 qore_socket_private& sock;
154 DLLLOCAL OptionalNonBlockingHelper(qore_socket_private& s,
bool n_set,
ExceptionSink* xs);
155 DLLLOCAL ~OptionalNonBlockingHelper();
158 class PrivateQoreSocketTimeoutBase {
160 hashdecl qore_socket_private* sock;
164 DLLLOCAL PrivateQoreSocketTimeoutBase(qore_socket_private* s) : sock(s), start(sock ? q_clock_getmicros() : 0) {
168 class PrivateQoreSocketTimeoutHelper :
public PrivateQoreSocketTimeoutBase {
172 DLLLOCAL PrivateQoreSocketTimeoutHelper(qore_socket_private* s,
const char* op);
173 DLLLOCAL ~PrivateQoreSocketTimeoutHelper();
176 class PrivateQoreSocketThroughputHelper :
public PrivateQoreSocketTimeoutBase {
180 DLLLOCAL PrivateQoreSocketThroughputHelper(qore_socket_private* s,
bool snd);
181 DLLLOCAL ~PrivateQoreSocketThroughputHelper();
183 DLLLOCAL
void finalize(
int64 bytes);
186 hashdecl qore_socket_private;
188 hashdecl qore_socket_op_helper {
190 qore_socket_private* s;
193 DLLLOCAL qore_socket_op_helper(qore_socket_private* sock);
194 DLLLOCAL ~qore_socket_op_helper();
197 class SSLSocketHelperHelper {
199 qore_socket_private* s;
200 SSLSocketHelper* ssl;
201 bool context_saved =
false;
204 DLLLOCAL SSLSocketHelperHelper(qore_socket_private* sock,
bool set_thread_context =
false);
206 DLLLOCAL ~SSLSocketHelperHelper();
208 DLLLOCAL
void error();
211 hashdecl qore_socket_private {
212 friend class PrivateQoreSocketTimeoutHelper;
213 friend class PrivateQoreSocketThroughputHelper;
216 static thread_local qore_socket_private* current_socket;
218 int sock, sfamily, port, stype, sprot;
221 int64 connection_id = 0;
225 std::string socketname;
227 std::string client_target;
228 SSLSocketHelper* ssl =
nullptr;
229 Queue* event_queue =
nullptr,
230 * warn_queue =
nullptr;
233 std::string assume_http_encoding =
"ISO-8859-1";
236 char rbuf[DEFAULT_SOCKET_BUFSIZE];
242 int64 tl_warning_us = 0;
243 double tp_warning_bs = 0;
244 int64 tp_bytes_sent = 0,
256 http_exp_chunked_body =
false,
257 ssl_accept_all_certs =
false,
258 ssl_capture_remote_cert =
false,
261 ssl_verify_mode = SSL_VERIFY_NONE;
269 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) :
270 sock(n_sock), sfamily(n_sfamily), port(-1), stype(n_stype), sprot(n_prot), enc(n_enc) {
273 DLLLOCAL ~qore_socket_private() {
277 assert(!event_queue);
281 DLLLOCAL
bool isOpen() {
282 return sock != QORE_INVALID_SOCKET;
285 DLLLOCAL
int close() {
286 int rc = close_internal();
289 if (http_exp_chunked_body)
290 http_exp_chunked_body =
false;
298 DLLLOCAL
int close_and_reset() {
299 assert(sock != QORE_INVALID_SOCKET);
303 rc = ::closesocket(sock);
308 if (!rc || sock_get_error() != EINTR)
312 sock = QORE_INVALID_SOCKET;
322 client_target.clear();
326 DLLLOCAL
int close_internal() {
329 ssl_err_str->deref();
330 ssl_err_str =
nullptr;
333 remote_cert->
deref(
nullptr);
334 remote_cert =
nullptr;
344 if (!socketname.empty()) {
346 unlink(socketname.c_str());
354 return close_and_reset();
360 DLLLOCAL
void setAssumedEncoding(
const char* str) {
361 assume_http_encoding = str;
364 DLLLOCAL
const char* getAssumedEncoding()
const {
365 return assume_http_encoding.c_str();
368 DLLLOCAL
int getSendTimeout()
const {
371 #if defined(HPUX) && defined(__ia64) && defined(__LP64__) 374 int size =
sizeof(
hashdecl timeval);
376 socklen_t size =
sizeof(
hashdecl timeval);
379 if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
382 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
385 DLLLOCAL
int getRecvTimeout()
const {
388 #if defined(HPUX) && defined(__ia64) && defined(__LP64__) 391 int size =
sizeof(
hashdecl timeval);
393 socklen_t size =
sizeof(
hashdecl timeval);
396 if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
399 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
402 DLLLOCAL
int getPort() {
404 if (sock == QORE_INVALID_SOCKET || (sfamily != AF_INET && sfamily != AF_INET6) || port > 0)
408 hashdecl sockaddr_storage addr;
409 #if defined(HPUX) && defined(__ia64) && defined(__LP64__) 411 int size =
sizeof addr;
413 socklen_t size =
sizeof addr;
416 if (getsockname(sock, (
struct sockaddr *)&addr, (socklen_t *)&size) < 0)
419 port = q_get_port_from_addr((
const struct sockaddr *)&addr);
424 switch (v.getType()) {
429 hdr.
sprintf(
"%s: " QLLD
"\r\n", key, v.getAsBigInt());
433 size_t offset = hdr.
size();
434 hdr.
sprintf(
"%f\r\n", v.getAsFloat());
438 q_fix_decimal(&hdr, offset);
447 hdr.
sprintf(
"%s: %d\r\n", key, (
int)v.getAsBool());
463 const char* key = hi.getKey();
464 if (addsize && !strcasecmp(key,
"transfer-encoding"))
466 if (addsize && !strcasecmp(key,
"content-length"))
471 do_header(key, hdr, li.getValue());
473 do_header(key, hdr, v);
477 if (size || addsize) {
478 hdr.
sprintf(
"Content-Length: " QSD
"\r\n", size);
484 DLLLOCAL
int listen(
int backlog = 20) {
485 if (sock == QORE_INVALID_SOCKET)
490 if (::listen(sock, backlog)) {
497 return ::listen(sock, backlog);
501 DLLLOCAL
int accept_intern(
ExceptionSink* xsink,
struct sockaddr *addr, socklen_t *size,
int timeout_ms = -1) {
505 if (timeout_ms >= 0 && !isDataAvailable(timeout_ms,
"accept", xsink)) {
512 int rc = ::accept(sock, addr, size);
513 if (rc != QORE_INVALID_SOCKET)
517 if (sock_get_error() == EINTR)
520 qore_socket_error(xsink,
"SOCKET-ACCEPT-ERROR",
"error in accept()", 0, 0, 0, addr);
528 if (sock == QORE_INVALID_SOCKET) {
529 xsink->
raiseException(
"SOCKET-NOT-OPEN",
"socket must be opened, bound, and in a listening state before new connections can be accepted");
534 se_in_op(
"Socket",
"accept", xsink);
537 se_in_op_thread(
"Socket",
"accept", xsink);
538 return QSE_IN_OP_THREAD;
542 if (sfamily == AF_UNIX) {
544 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"UNIX sockets are not available under Windows");
547 hashdecl sockaddr_un addr_un;
549 #if defined(HPUX) && defined(__ia64) && defined(__LP64__) 552 int size =
sizeof(
hashdecl sockaddr_un);
554 socklen_t size =
sizeof(
hashdecl sockaddr_un);
556 rc = accept_intern(xsink, (
struct sockaddr *)&addr_un, (socklen_t *)&size, timeout_ms);
559 if (rc >= 0 && source) {
561 addr->
sprintf(
"UNIX socket: %s", socketname.c_str());
562 source->priv->setAddress(addr);
563 source->priv->setHostName(
"localhost");
566 }
else if (sfamily == AF_INET || sfamily == AF_INET6) {
567 hashdecl sockaddr_storage addr_in;
568 #if defined(HPUX) && defined(__ia64) && defined(__LP64__) 571 int size =
sizeof(addr_in);
573 socklen_t size =
sizeof(addr_in);
576 rc = accept_intern(xsink, (
struct sockaddr *)&addr_in, (socklen_t *)&size, timeout_ms);
579 if (rc >= 0 && source) {
580 char host[NI_MAXHOST + 1];
581 char service[NI_MAXSERV + 1];
583 if (!getnameinfo((
struct sockaddr *)&addr_in, qore_get_in_len((
struct sockaddr *)&addr_in), host,
sizeof(host), service,
sizeof(service), NI_NUMERICSERV)) {
584 source->priv->setHostName(host);
588 char ifname[INET6_ADDRSTRLEN];
589 if (inet_ntop(addr_in.ss_family, qore_get_in_addr((
struct sockaddr *)&addr_in), ifname,
sizeof(ifname))) {
591 source->priv->setAddress(ifname);
596 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"do not know how to accept connections with address family %d", sfamily);
602 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_SOCKET)
const {
621 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
624 event_queue->deref(xsink);
625 event_queue =
nullptr;
628 warn_queue->deref(xsink);
629 warn_queue =
nullptr;
630 if (warn_callback_arg) {
631 warn_callback_arg.
discard(xsink);
632 warn_callback_arg.clear();
642 event_queue->deref(xsink);
646 event_data = with_data;
649 DLLLOCAL
void do_start_ssl_event() {
651 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_START_SSL));
655 DLLLOCAL
void do_ssl_established_event() {
660 event_queue->pushAndTakeRef(h);
664 DLLLOCAL
void do_connect_event(
int af,
const struct sockaddr* addr,
const char* target,
const char* service =
nullptr,
int prt = -1) {
673 q_af_to_hash(af, *h,
nullptr);
679 event_queue->pushAndTakeRef(h);
683 DLLLOCAL
void do_connected_event() {
685 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CONNECTED));
689 DLLLOCAL
void do_data_event_intern(
int event,
int source,
const QoreStringNode& str)
const {
690 assert(event_queue && event_data && str.
size());
693 event_queue->pushAndTakeRef(h.release());
696 DLLLOCAL
void do_data_event(
int event,
int source,
const QoreStringNode& str)
const {
697 if (event_queue && event_data && str.
size()) {
698 do_data_event_intern(event, source, str);
702 DLLLOCAL
void do_data_event(
int event,
int source,
const BinaryNode& b)
const {
703 if (event_queue && event_data && b.
size()) {
706 event_queue->pushAndTakeRef(h.release());
710 DLLLOCAL
void do_data_event(
int event,
int source,
const void* data,
size_t size)
const {
711 if (event_queue && event_data && size) {
716 event_queue->pushAndTakeRef(h.release());
720 DLLLOCAL
void do_header_event(
int event,
int source,
const QoreHashNode& hdr)
const {
721 if (event_queue && event_data && !hdr.
empty()) {
724 event_queue->pushAndTakeRef(h.release());
731 if (event == QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED)
736 event_queue->pushAndTakeRef(h);
740 DLLLOCAL
void do_read_http_header(
int event,
const QoreHashNode* headers,
int source) {
744 event_queue->pushAndTakeRef(h);
748 DLLLOCAL
void do_send_http_message_event(
const QoreString& str,
const QoreHashNode* headers,
int source) {
750 QoreHashNode* h = getEvent(QORE_EVENT_HTTP_SEND_MESSAGE, source);
754 event_queue->pushAndTakeRef(h);
758 DLLLOCAL
void do_close_event() {
760 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
764 DLLLOCAL
void do_read_event(
size_t bytes_read,
size_t total_read,
size_t bufsize = 0,
int source = QORE_SOURCE_SOCKET) {
767 QoreHashNode* h = getEvent(QORE_EVENT_PACKET_READ, source);
773 event_queue->pushAndTakeRef(h);
777 DLLLOCAL
void do_send_event(
int bytes_sent,
int total_sent,
int bufsize) {
784 event_queue->pushAndTakeRef(h);
788 DLLLOCAL
void do_resolve_event(
const char* host,
const char* service = 0) {
796 event_queue->pushAndTakeRef(h);
800 DLLLOCAL
void do_resolved_event(
const struct sockaddr* addr) {
803 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_RESOLVED);
809 int prt = q_get_port_from_addr(addr);
812 q_af_to_hash(addr->sa_family, *h,
nullptr);
813 event_queue->pushAndTakeRef(h);
817 DLLLOCAL
int64 getObjectIDForEvents()
const {
821 DLLLOCAL
int connectUNIX(
const char* p,
int sock_type,
int protocol,
ExceptionSink* xsink) {
824 QORE_TRACE(
"connectUNIX()");
827 xsink->
raiseException(
"SOCKET-CONNECTUNIX-ERROR",
"UNIX sockets are not available under Windows");
833 printd(5,
"qore_socket_private::connectUNIX(%s)\n", p);
835 hashdecl sockaddr_un addr;
837 addr.sun_family = AF_UNIX;
839 strncpy(addr.sun_path, p,
sizeof(addr.sun_path) - 1);
840 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
841 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_SOCKET_ERROR) {
842 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"error connecting to UNIX socket: '%s'", p);
846 do_connect_event(AF_UNIX, (sockaddr*)&addr, p);
848 if (!::connect(sock, (
const sockaddr *)&addr,
sizeof(
struct sockaddr_un)))
852 if (sock_get_error() == EINTR)
858 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, p);
864 socketname = addr.sun_path;
867 do_connected_event();
879 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
const char* cname,
const char* mname,
ExceptionSink* xsink)
const {
881 assert(read || write);
882 if (sock == QORE_INVALID_SOCKET) {
883 se_not_open(cname, mname, xsink);
887 return asyncIoWait(timeout_ms, read, write, xsink);
890 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
ExceptionSink* xsink)
const {
892 #if defined HAVE_POLL 893 return poll_intern(xsink, timeout_ms, read, write);
894 #elif defined HAVE_SELECT 895 return select_intern(xsink, timeout_ms, read, write);
897 #error no async socket operations supported 901 #if defined HAVE_POLL 902 DLLLOCAL
int poll_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
909 pollfd fds = {sock, arg, 0};
911 rc = poll(&fds, 1, timeout_ms);
912 if (rc == -1 && errno == EINTR)
917 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"poll(2) returned an error");
918 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
923 #elif defined HAVE_SELECT 924 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
925 bool aborted =
false;
926 int rc = select_intern(xsink, timeout_ms, read, write, aborted);
927 if (rc != QORE_SOCKET_ERROR && aborted)
932 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write,
bool& aborted)
const {
939 if (sock >= FD_SETSIZE) {
940 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);
955 tv.tv_sec = timeout_ms / 1000;
956 tv.tv_usec = (timeout_ms % 1000) * 1000;
958 fd_set* readfd = read ? &sfs : 0;
959 fd_set* writefd = write ? &sfs : 0;
961 rc = select(sock + 1, readfd, writefd, &err, &tv);
963 if (rc != QORE_SOCKET_ERROR) {
964 if (FD_ISSET(sock, &err))
968 if (sock_get_error() != EINTR)
971 if (rc == QORE_SOCKET_ERROR) {
974 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"select(2) returned an error");
981 DLLLOCAL
bool tryReadSocketData(
const char* mname,
ExceptionSink* xsink) {
986 return asyncIoWait(0,
true,
false,
"Socket", mname, xsink);
990 int rc = ssl->doSSLRW(xsink, mname, rbuf, 1, 0, PEEK,
false);
991 if (*xsink || (rc == QSE_TIMEOUT)) {
994 return rc > 0 ? true :
false;
997 DLLLOCAL
bool isSocketDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
998 return asyncIoWait(timeout_ms,
true,
false,
"Socket", mname, xsink);
1001 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1004 return isSocketDataAvailable(timeout_ms, mname, xsink);
1007 DLLLOCAL
bool isWriteFinished(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1008 return asyncIoWait(timeout_ms,
false,
true,
"Socket", mname, xsink);
1011 DLLLOCAL
int close_and_exit() {
1012 if (sock != QORE_INVALID_SOCKET)
1017 DLLLOCAL
int connectINETTimeout(
int timeout_ms,
const struct sockaddr* ai_addr,
qore_size_t ai_addrlen,
ExceptionSink* xsink,
bool only_timeout) {
1019 PrivateQoreSocketTimeoutHelper toh(
this,
"connect");
1022 if (!::connect(sock, ai_addr, ai_addrlen))
1026 if (sock_get_error() != EAGAIN) {
1027 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1035 if (errno != EINPROGRESS)
1044 bool aborted =
false;
1045 int rc = select_intern(xsink, timeout_ms,
false,
true, aborted);
1051 if (rc != QORE_SOCKET_ERROR && aborted) {
1052 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1056 int rc = asyncIoWait(timeout_ms,
false,
true,
"Socket",
"connectINETTimeout", xsink);
1062 if (rc == QORE_SOCKET_ERROR && sock_get_error() != EINTR) {
1064 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in asyncIoWait() with Socket::connect() with timeout", 0, 0, 0, ai_addr);
1066 }
else if (rc > 0) {
1068 socklen_t lon =
sizeof(int);
1071 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (GETSOCKOPT_ARG_4)(&val), &lon) == QORE_SOCKET_ERROR) {
1073 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()", 0, 0, 0, ai_addr);
1082 qore_socket_error_intern(val, xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()", 0, 0, 0, ai_addr);
1090 concat_target(*(*desc), ai_addr);
1100 DLLLOCAL
int sock_errno_err(
const char* err,
const char* desc,
ExceptionSink* xsink) {
1101 sock = QORE_INVALID_SOCKET;
1102 qore_socket_error(xsink, err, desc);
1106 DLLLOCAL
int set_non_blocking(
bool non_blocking,
ExceptionSink* xsink) {
1110 if (sock == QORE_INVALID_SOCKET) {
1111 assert(!xsink || *xsink);
1116 u_long mode = non_blocking ? 1 : 0;
1117 int rc = ioctlsocket(sock, FIONBIO, &mode);
1118 if (check_windows_rc(rc))
1119 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in ioctlsocket(FIONBIO)", xsink);
1124 if ((arg = fcntl(sock, F_GETFL, 0)) < 0)
1125 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() getting socket descriptor status flag", xsink);
1132 if (fcntl(sock, F_SETFL, arg) < 0)
1133 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() setting socket descriptor status flag", xsink);
1139 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) {
1141 family = q_get_af(family);
1142 type = q_get_sock_type(type);
1144 QORE_TRACE(
"qore_socket_private::connectINET()");
1149 printd(5,
"qore_socket_private::connectINET(%s:%s, %dms)\n", host, service, timeout_ms);
1151 do_resolve_event(host, service);
1154 if (ai.
getInfo(xsink, host, service, family, 0, type, protocol))
1161 for (
struct addrinfo *p = aip; p; p = p->ai_next)
1162 do_resolved_event(p->ai_addr);
1164 int prt = q_get_port_from_addr(aip->ai_addr);
1166 for (
struct addrinfo *p = aip; p; p = p->ai_next) {
1167 if (!connectINETIntern(host, service, p->ai_family, p->ai_addr, p->ai_addrlen, p->ai_socktype, p->ai_protocol, prt, timeout_ms, xsink,
true))
1174 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1178 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) {
1180 printd(5,
"qore_socket_private::connectINETIntern() host: %s service: %s family: %d timeout_ms: %d\n", host, service, ai_family, timeout_ms);
1181 if ((sock = socket(ai_family, ai_socktype, ai_protocol)) == QORE_INVALID_SOCKET) {
1182 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"cannot establish a connection to %s:%s", host, service);
1191 if (timeout_ms >= 0) {
1193 if (set_non_blocking(
true, xsink))
1194 return close_and_exit();
1196 do_connect_event(ai_family, ai_addr, host, service, prt);
1198 rc = connectINETTimeout(timeout_ms, ai_addr, ai_addrlen, xsink, only_timeout);
1202 if (set_non_blocking(
false, xsink))
1203 return close_and_exit();
1205 do_connect_event(ai_family, ai_addr, host, service, prt);
1208 rc = ::connect(sock, ai_addr, ai_addrlen);
1211 if (!rc || sock_get_error() != EINTR)
1217 if (!only_timeout || errno == ETIMEDOUT)
1218 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1220 return close_and_exit();
1223 sfamily = ai_family;
1224 stype = ai_socktype;
1225 sprot = ai_protocol;
1229 do_connected_event();
1232 client_target = host;
1236 DLLLOCAL
int upgradeClientToSSLIntern(
const char* mname,
const char* sni_target_host, X509* cert, EVP_PKEY* pkey,
int timeout_ms,
ExceptionSink* xsink) {
1238 SSLSocketHelperHelper sshh(
this,
true);
1241 do_start_ssl_event();
1243 if (!sni_target_host && !client_target.empty()) {
1244 sni_target_host = client_target.c_str();
1246 if ((rc = ssl->setClient(mname, sni_target_host, sock, cert, pkey, xsink)) || ssl->connect(mname, timeout_ms, xsink)) {
1248 return rc ? rc : -1;
1250 do_ssl_established_event();
1255 DLLLOCAL
int upgradeServerToSSLIntern(
const char* mname, X509* cert, EVP_PKEY* pkey,
int timeout_ms,
ExceptionSink* xsink) {
1258 SSLSocketHelperHelper sshh(
this,
true);
1260 do_start_ssl_event();
1261 if (ssl->setServer(mname, sock, cert, pkey, xsink) || ssl->accept(mname, timeout_ms, xsink)) {
1265 do_ssl_established_event();
1271 DLLLOCAL
int openUNIX(
int sock_type = SOCK_STREAM,
int protocol = 0) {
1272 if (sock != QORE_INVALID_SOCKET)
1275 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_INVALID_SOCKET) {
1287 DLLLOCAL
int openINET(
int family = AF_INET,
int sock_type = SOCK_STREAM,
int protocol = 0) {
1288 if (sock != QORE_INVALID_SOCKET)
1291 if ((sock = socket(family, sock_type, protocol)) == QORE_INVALID_SOCKET)
1301 DLLLOCAL
int reuse(
int opt) {
1303 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_ARG_4)&opt,
sizeof(
int));
1307 DLLLOCAL
int bindIntern(
struct sockaddr* ai_addr,
size_t ai_addrlen,
int prt,
bool reuseaddr,
ExceptionSink* xsink = 0) {
1310 if ((::bind(sock, ai_addr, ai_addrlen)) == QORE_SOCKET_ERROR) {
1312 qore_socket_error(xsink,
"SOCKET-BIND-ERROR",
"error in bind()", 0, 0, 0, ai_addr);
1322 #if defined(HPUX) && defined(__ia64) && defined(__LP64__) 1324 int len = ai_addrlen;
1326 socklen_t len = ai_addrlen;
1329 if (getsockname(sock, ai_addr, &len))
1332 port = q_get_port_from_addr(ai_addr);
1338 DLLLOCAL
int bindUNIX(
ExceptionSink* xsink,
const char* name,
int socktype = SOCK_STREAM,
int protocol = 0) {
1341 xsink->
raiseException(
"SOCKET-BINDUNIX-ERROR",
"UNIX sockets are not available under Windows");
1347 if (openUNIX(socktype, protocol)) {
1348 xsink->
raiseErrnoException(
"SOCKET-BIND-ERROR", errno,
"error opening UNIX socket ('%s') for bind", name);
1352 hashdecl sockaddr_un addr;
1353 addr.sun_family = AF_UNIX;
1355 strncpy(addr.sun_path, name,
sizeof(addr.sun_path) - 1);
1356 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1358 if (bindIntern((sockaddr*)&addr,
sizeof(
struct sockaddr_un), -1,
false, xsink))
1362 socketname = addr.sun_path;
1369 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) {
1371 family = q_get_af(family);
1372 socktype = q_get_sock_type(socktype);
1377 do_resolve_event(name, service);
1378 if (ai.
getInfo(xsink, name, service, family, AI_PASSIVE, socktype, protocol))
1384 for (
struct addrinfo *p = aip; p; p = p->ai_next)
1385 do_resolved_event(p->ai_addr);
1388 if (openINET(aip->ai_family, aip->ai_socktype, protocol)) {
1389 qore_socket_error(xsink,
"SOCKET-BINDINET-ERROR",
"error opening socket for bind", 0, name, service);
1393 int prt = q_get_port_from_addr(aip->ai_addr);
1397 for (
struct addrinfo *p = aip; p; p = p->ai_next) {
1398 if (!bindIntern(p->ai_addr, p->ai_addrlen, prt, reuseaddr)) {
1403 en = sock_get_raw_error();
1408 qore_socket_error_intern(en, xsink,
"SOCKET-BIND-ERROR",
"error binding on socket", 0, name, service);
1415 if (sock == QORE_INVALID_SOCKET) {
1416 se_not_open(
"Socket",
"getPeerInfo", xsink);
1420 hashdecl sockaddr_storage addr;
1421 socklen_t len =
sizeof addr;
1422 if (getpeername(sock, (
struct sockaddr*)&addr, &len)) {
1423 qore_socket_error(xsink,
"SOCKET-GETPEERINFO-ERROR",
"error in getpeername()");
1427 return getAddrInfo(addr, len, host_lookup);
1433 if (sock == QORE_INVALID_SOCKET) {
1434 se_not_open(
"Socket",
"getSocketInfo", xsink);
1438 hashdecl sockaddr_storage addr;
1439 #if defined(HPUX) && defined(__ia64) && defined(__LP64__) 1441 int len =
sizeof addr;
1443 socklen_t len =
sizeof addr;
1446 if (getsockname(sock, (
struct sockaddr*)&addr, &len)) {
1447 qore_socket_error(xsink,
"SOCKET-GETSOCKETINFO-ERROR",
"error in getsockname()");
1451 return getAddrInfo(addr, len, host_lookup);
1454 DLLLOCAL
QoreHashNode* getAddrInfo(
const struct sockaddr_storage& addr, socklen_t len,
bool host_lookup =
true)
const {
1457 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1459 char host[NI_MAXHOST + 1];
1461 if (!getnameinfo((
struct sockaddr*)&addr, qore_get_in_len((
struct sockaddr*)&addr), host,
sizeof(host), 0, 0, 0)) {
1469 char ifname[INET6_ADDRSTRLEN];
1470 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr*)&addr), ifname,
sizeof(ifname))) {
1477 if (addr.ss_family == AF_INET) {
1478 hashdecl sockaddr_in* s = (
hashdecl sockaddr_in*)&addr;
1479 tport = ntohs(s->sin_port);
1481 hashdecl sockaddr_in6* s = (
hashdecl sockaddr_in6*)&addr;
1482 tport = ntohs(s->sin6_port);
1488 else if (addr.ss_family == AF_UNIX) {
1489 assert(!socketname.empty());
1505 hashdecl sockaddr_storage addr;
1507 socklen_t len =
sizeof addr;
1508 if (getpeername(sock, (
struct sockaddr*)&addr, &len))
1511 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1513 char ifname[INET6_ADDRSTRLEN];
1514 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr *)&addr), ifname,
sizeof(ifname))) {
1519 char host[NI_MAXHOST + 1];
1520 if (!getnameinfo((
struct sockaddr *)&addr, qore_get_in_len((
struct sockaddr *)&addr), host,
sizeof(host), 0, 0, 0))
1524 else if (addr.ss_family == AF_UNIX) {
1526 hashdecl sockaddr_un *addr_un = (
hashdecl sockaddr_un *)&addr;
1527 astr->
sprintf(
"UNIX socket: %s", addr_un->sun_path);
1538 assert(sock != QORE_INVALID_SOCKET);
1543 buf = rbuf + bufoffset;
1561 if (timeout != -1 && !isDataAvailable(timeout, meth, xsink)) {
1564 se_timeout(
"Socket", meth, timeout, xsink);
1573 rc = ::recv(sock, rbuf, DEFAULT_SOCKET_BUFSIZE, flags);
1574 if (rc == QORE_SOCKET_ERROR) {
1579 if (errno == ECONNRESET) {
1580 se_closed(
"Socket", meth, xsink);
1584 qore_socket_error(xsink,
"SOCKET-RECV-ERROR",
"error in recv()", meth);
1593 rc = ssl->read(meth, rbuf, DEFAULT_SOCKET_BUFSIZE, timeout, xsink);
1608 do_read_event(rc, rc);
1624 if (sock == QORE_INVALID_SOCKET) {
1625 se_not_open(
"Socket", meth, xsink);
1630 PrivateQoreSocketThroughputHelper th(
this,
false);
1645 rc = brecv(xsink, meth, buf, 1, 0, timeout,
false);
1653 se_closed(
"Socket", meth, xsink);
1655 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");
1661 if (++count == QORE_MAX_HEADER_SIZE) {
1662 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"header size cannot exceed " QSD
" bytes", count);
1673 if (exit_early && hdr->
empty())
1680 }
else if (c ==
'\r') {
1695 case 0: hdr->concat(
'\r');
break;
1696 case 1: hdr->concat(
"\r\n");
break;
1697 case 2: hdr->concat(
"\r\n\r");
break;
1698 case 3: hdr->concat(
'\n');
break;
1708 th.finalize(hdr->
size());
1710 return hdr.release();
1715 if (sock == QORE_INVALID_SOCKET) {
1716 se_not_open(
"Socket",
"recv", xsink);
1722 se_in_op(
"Socket",
"recv", xsink);
1725 se_in_op_thread(
"Socket",
"recv", xsink);
1729 PrivateQoreSocketThroughputHelper th(
this,
false);
1731 qore_size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
1738 rc = brecv(xsink,
"recv", buf, bs, 0, timeout,
false);
1741 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));
1749 do_read_event(rc, str->
size(), bufsize, source);
1755 if ((bufsize - str->
size()) < bs)
1756 bs = bufsize - str->
size();
1760 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");
1766 th.finalize(str->
size());
1773 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
1775 return str.release();
1780 if (sock == QORE_INVALID_SOCKET) {
1781 se_not_open(
"Socket",
"recv", xsink);
1787 se_in_op(
"Socket",
"recv", xsink);
1790 se_in_op_thread(
"Socket",
"recv", xsink);
1794 PrivateQoreSocketThroughputHelper th(
this,
false);
1800 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
1807 do_read_event(rc, rc);
1810 if (isDataAvailable(0,
"recv", xsink)) {
1812 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
1818 th.finalize(str->
size());
1824 do_read_event(rc, str->
size());
1825 }
while (isDataAvailable(0,
"recv", xsink));
1828 th.finalize(str->
size());
1836 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
1838 return str.release();
1845 if (sock == QORE_INVALID_SOCKET) {
1846 se_not_open(
"Socket",
"recvBinary", xsink);
1852 se_in_op(
"Socket",
"recvBinary", xsink);
1855 se_in_op_thread(
"Socket",
"recvBinary", xsink);
1859 PrivateQoreSocketThroughputHelper th(
this,
false);
1861 qore_size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
1867 rc = brecv(xsink,
"recvBinary", buf, bs, 0, timeout);
1876 if ((bufsize - b->
size()) < bs)
1877 bs = bufsize - b->
size();
1881 th.finalize(b->
size());
1891 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
1893 printd(5,
"qore_socket_private::recvBinary() received " QSD
" byte(s), bufsize=" QSD
", blen=" QSD
"\n", b->
size(), bufsize, b->
size());
1899 if (sock == QORE_INVALID_SOCKET) {
1900 se_not_open(
"Socket",
"recvBinary", xsink);
1906 se_in_op(
"Socket",
"recvBinary", xsink);
1909 se_in_op_thread(
"Socket",
"recvBinary", xsink);
1913 PrivateQoreSocketThroughputHelper th(
this,
false);
1920 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
1927 do_read_event(rc, rc);
1930 if (isDataAvailable(0,
"recvBinary", xsink)) {
1932 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
1937 th.finalize(b->
size());
1944 do_read_event(rc, b->
size());
1945 }
while (isDataAvailable(0,
"recvBinary", xsink));
1948 th.finalize(b->
size());
1954 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
1962 if (sock == QORE_INVALID_SOCKET) {
1963 se_not_open(
"Socket",
"recvToOutputStream", xsink);
1968 se_in_op(
"Socket",
"recvToOutputStream", xsink);
1971 se_in_op_thread(
"Socket",
"recvToOutputStream", xsink);
1975 qore_socket_op_helper oh(
this);
1979 while (size < 0 || br < size) {
1981 int bn = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - br, DEFAULT_SOCKET_BUFSIZE);
1983 qore_offset_t rc = brecv(xsink,
"recvToOutputStream", buf, bn, 0, timeout);
1992 xsink->
raiseException(
"SOCKET-RECV-ERROR",
"Unexpected end of stream");
1998 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, buf, rc);
2004 os->
write(buf, rc, xsink);
2023 do_data_event(QORE_EVENT_HTTP_HEADERS_READ, source, **hdr);
2024 return hdr.release();
2028 qore_offset_t& rc,
int source,
const char* headers_raw_key =
"headers-raw") {
2037 const char* buf = hdr->getBuffer();
2040 if ((p = (
char*)strstr(buf,
"\r\n"))) {
2043 }
else if ((p = (
char*)strchr(buf,
'\n'))) {
2046 }
else if ((p = (
char*)strchr(buf,
'\r'))) {
2052 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"invalid header received with embedded nulls in Socket::readHTTPHeader()");
2057 if (!(t1 = (
char*)strstr(buf,
"HTTP/"))) {
2058 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"missing HTTP version string in first header line in Socket::readHTTPHeader()");
2065 int flags = CHF_PROCESS;
2072 flags |= CHF_HTTP11;
2077 const char* info_key;
2079 char* t2 = (
char*)strchr(buf + 8,
' ');
2082 if (isdigit(*(t2))) {
2084 if (strlen(t2) > 4) {
2091 info_key =
"response-uri";
2093 char* t2 = (
char*)strchr(buf,
' ');
2098 t1 = strchr(t2,
' ');
2106 info_key =
"request-uri";
2107 flags |= CHF_REQUEST;
2111 if (info || (event_queue && event_data)) {
2113 if (info && event_queue && event_data) {
2116 if (event_queue && event_data) {
2117 do_data_event_intern(QORE_EVENT_SOCKET_DATA_READ, source, **status_line);
2120 info->
setKeyValue(info_key, *status_line,
nullptr);
2122 status_line.release();
2125 bool close = convertHeaderToHash(*h, p, flags, info, &http_exp_chunked_body, headers_raw_key);
2126 do_read_http_header(QORE_EVENT_HTTP_MESSAGE_RECEIVED, *h, source);
2129 if ((flags & CHF_REQUEST) && info)
2145 arg->
setKeyValue(
"send_aborted", send_aborted, xsink);
2146 args->push(arg,
nullptr);
2149 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2154 if (runCallback(xsink, cname, mname, rv, callback, l,
nullptr))
2157 switch (rv->getType()) {
2165 xsink->
raiseException(
"HTTP-TRAILER-ERROR",
"chunked callback returned type '%s'; expecting 'hash' or 'NOTHING'", rv->getTypeName());
2177 args->push(arg,
nullptr);
2180 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2198 if (sock == QORE_INVALID_SOCKET) {
2199 se_not_open(cname, mname, xsink);
2200 return QSE_NOT_OPEN;
2208 assert(!aborted || !(*aborted));
2210 if (sock == QORE_INVALID_SOCKET) {
2211 se_not_open(cname, mname, xsink);
2212 return QSE_NOT_OPEN;
2216 se_in_op(cname, mname, xsink);
2219 se_in_op_thread(cname, mname, xsink);
2223 PrivateQoreSocketThroughputHelper th(
this,
true);
2226 bool nb = (timeout_ms >= 0);
2228 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2232 qore_socket_op_helper oh(
this);
2241 bool data_available = tryReadSocketData(mname, xsink);
2243 if (data_available || *xsink) {
2245 return *xsink ? -1 : 0;
2251 rc = runCallback(xsink, cname, mname, res, send_callback, &l);
2260 const char* data_ptr =
nullptr;
2261 size_t data_size = 0;
2263 switch (res->getType()) {
2271 data_ptr = str->
c_str();
2272 data_size = str->
size();
2284 data_ptr =
static_cast<const char*
>(b->
getPtr());
2285 data_size = b->
size();
2297 const char* key = hi.getKey();
2304 do_header(key, buf, li.getValue());
2306 do_header(key, buf, v);
2317 xsink->
raiseException(
"SOCKET-CALLBACK-ERROR",
"HTTP chunked data callback returned type '%s'; expecting one of: 'string', 'binary', 'hash', 'nothing' (or 'NULL')", res->getTypeName());
2323 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2329 if (data_ptr && data_size) {
2330 rc = sendIntern(xsink, cname, mname, data_ptr, data_size, timeout_ms, total,
true);
2335 if (buf.
empty() && (!data_ptr || !data_size)) {
2336 buf.
set(
"0\r\n\r\n");
2340 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2346 switch (res->getType()) {
2349 if (!str->
empty()) {
2350 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *str);
2358 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *b);
2365 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, source, *h);
2373 if (aborted && *xsink) {
2374 bool data_available = tryReadSocketData(mname, xsink);
2376 if (data_available) {
2378 return *xsink ? -1 : 0;
2387 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2393 return rc < 0 || sock == QORE_INVALID_SOCKET ? -1 : 0;
2396 DLLLOCAL
int sendIntern(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
qore_size_t size,
int timeout_ms,
int64& total,
bool stream =
false) {
2402 bool nb = (timeout_ms >= 0);
2407 rc = ssl->write(mname, buf + bs, size - bs, timeout_ms, xsink);
2410 rc = ::send(sock, buf + bs, size - bs, 0);
2417 if (nb && (errno == EAGAIN
2419 || errno == EWOULDBLOCK
2422 if (!isWriteFinished(timeout_ms, mname, xsink)) {
2425 se_timeout(
"Socket", mname, timeout_ms, xsink);
2431 if (errno != EINTR) {
2433 xsink->
raiseErrnoException(
"SOCKET-SEND-ERROR", errno,
"error while executing %s::%s()", cname, mname);
2437 if (!stream && errno == EPIPE)
2441 if (!stream && errno == ECONNRESET)
2452 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2457 do_send_event(rc, bs, size);
2468 DLLLOCAL
int send(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
qore_size_t size,
int timeout_ms = -1,
int source = QORE_SOURCE_SOCKET) {
2470 if (sock == QORE_INVALID_SOCKET) {
2471 se_not_open(cname, mname, xsink);
2473 return QSE_NOT_OPEN;
2477 se_in_op(cname, mname, xsink);
2480 se_in_op_thread(cname, mname, xsink);
2487 PrivateQoreSocketThroughputHelper th(
this,
true);
2490 bool nb = (timeout_ms >= 0);
2492 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2497 qore_offset_t rc = sendIntern(xsink, cname, mname, buf, size, timeout_ms, total);
2500 if (rc > 0 && source > 0) {
2501 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, buf, size);
2504 return rc < 0 || sock == QORE_INVALID_SOCKET ? rc : 0;
2508 if (sock == QORE_INVALID_SOCKET) {
2509 se_not_open(
"Socket",
"sendFromInputStream", xsink);
2514 se_in_op(
"Socket",
"sendFromInputStream", xsink);
2517 se_in_op_thread(
"Socket",
"sendFromInputStream", xsink);
2521 qore_socket_op_helper oh(
this);
2523 PrivateQoreSocketThroughputHelper th(
this,
true);
2526 bool nb = (timeout >= 0);
2528 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2532 char buf[DEFAULT_SOCKET_BUFSIZE];
2535 while (size < 0 || sent < size) {
2536 int64 toRead = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - sent, DEFAULT_SOCKET_BUFSIZE);
2540 r = is->
read(buf, toRead, xsink);
2549 xsink->
raiseException(
"SOCKET-SEND-ERROR",
"Unexpected end of stream");
2555 qore_offset_t rc = sendIntern(xsink,
"Socket",
"sendFromInputStream", buf, r, timeout, total);
2559 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, QORE_SOURCE_SOCKET, buf, r);
2566 if (sock == QORE_INVALID_SOCKET) {
2567 se_not_open(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2572 se_in_op(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2575 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2579 qore_socket_op_helper oh(
this);
2581 PrivateQoreSocketThroughputHelper th(
this,
true);
2584 bool nb = (timeout >= 0);
2586 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2592 buf->preallocate(max_chunk_size);
2598 r = is->
read((
void*)buf->getPtr(),
sizeof(max_chunk_size), xsink);
2605 str.
sprintf(
"%x\r\n", (
int)r);
2606 int rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2610 bool trailers =
false;
2614 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", (
const char*)buf->getPtr(), r, timeout, total,
true);
2617 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, QORE_SOURCE_SOCKET, buf->getPtr(), r);
2618 }
else if (trailer_callback) {
2622 if (runTrailerCallback(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", *trailer_callback, l, h))
2626 do_headers(str, *h, 0,
false);
2628 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2632 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, **h);
2640 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2654 if (sock == QORE_INVALID_SOCKET) {
2655 se_not_open(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2660 se_in_op(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2663 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2673 const char* key = hi.getKey();
2678 do_header(key, buf, li.getValue());
2681 do_header(key, buf, v);
2686 sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyTrailer", buf.
getBuffer(), buf.
size(), timeout, total,
true);
2688 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, *headers);
2693 const char* method,
const char* path,
const char* http_version,
const QoreHashNode* headers,
2701 hdr.sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
2708 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
2709 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
2721 hdr.sprintf(
"HTTP/%s %03d %s", http_version, code, desc);
2729 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
2730 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
2739 assert(!(data && send_callback));
2740 assert(!(data && input_stream));
2741 assert(!(send_callback && input_stream));
2744 do_send_http_message_event(hdr, headers, source);
2749 do_headers(hdr, headers, size && data ? size : 0);
2755 if ((rc = send(xsink, cname, mname, hdr.
c_str(), hdr.
size(), timeout_ms, -1)))
2760 int rc = send(xsink, cname, mname, (
char*)data, size, timeout_ms, -1);
2763 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, *body);
2765 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, data, size);
2769 }
else if (send_callback) {
2771 assert(!aborted || !(*aborted));
2772 return sendHttpChunkedWithCallback(xsink, cname, mname, *send_callback, *l, source, timeout_ms, aborted);
2773 }
else if (input_stream) {
2775 sendHttpChunkedBodyFromInputStream(input_stream, max_chunk_size, timeout_ms, xsink, l, trailer_callback);
2776 return *xsink ? -1 : 0;
2785 if (sock == QORE_INVALID_SOCKET) {
2786 se_not_open(cname,
"readHTTPChunkedBodyBinary", xsink);
2791 se_in_op(cname,
"readHTTPChunkedBodyBinary", xsink);
2794 se_in_op_thread(cname,
"readHTTPChunkedBodyBinary", xsink);
2799 if (http_exp_chunked_body)
2800 http_exp_chunked_body =
false;
2802 qore_socket_op_helper oh(
this);
2815 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 1, 0, timeout,
false);
2819 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
2826 if (!state && c ==
'\r')
2828 else if (state && c ==
'\n')
2842 char* p = (
char*)strchr(str.
getBuffer(),
';');
2845 long size = strtol(str.
c_str(), 0, 16);
2846 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
size(), source);
2852 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
2859 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
2863 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, bs, 0, timeout,
false);
2868 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
2873 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, buf, (
size_t)rc);
2877 os->
write(buf, rc, xsink);
2899 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 2 - br, 0, timeout,
false);
2903 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
2910 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
2912 if (recv_callback && !os) {
2913 if (runDataCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, *b,
true))
2929 if (!recv_callback && !os) {
2937 return recv_callback ? 0 : h.release();
2939 if (recv_callback) {
2942 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
2943 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
2946 if (recv_callback) {
2947 runHeaderCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, h->
empty() ? nullptr : *h,
2948 info.release(),
false, obj);
2959 if (sock == QORE_INVALID_SOCKET) {
2960 se_not_open(cname,
"readHTTPChunkedBody", xsink);
2965 se_in_op(cname,
"readHTTPChunkedBody", xsink);
2968 se_in_op_thread(cname,
"readHTTPChunkedBody", xsink);
2973 if (http_exp_chunked_body)
2974 http_exp_chunked_body =
false;
2976 qore_socket_op_helper oh(
this);
2989 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 1, 0, timeout,
false);
2993 se_closed(cname,
"readHTTPChunkedBody", xsink);
3000 if (!state && c ==
'\r')
3002 else if (state && c ==
'\n')
3016 char* p = (
char*)strchr(str.
getBuffer(),
';');
3020 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
strlen(), source);
3026 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3036 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3041 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, bs, 0, timeout,
false);
3045 se_closed(cname,
"readHTTPChunkedBody", xsink);
3051 buf->concat(tbuf, rc);
3053 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, tbuf, (
size_t)rc);
3069 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 2 - br, 0, timeout,
false);
3073 se_closed(cname,
"readHTTPChunkedBody", xsink);
3080 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3082 if (recv_callback) {
3083 if (runDataCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, *buf,
true))
3096 if (!recv_callback) {
3104 return recv_callback ? 0 : h.release();
3106 if (recv_callback) {
3109 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3110 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3113 if (recv_callback) {
3114 runHeaderCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, h->
empty() ? nullptr : *h,
3115 info.release(),
false, obj);
3122 DLLLOCAL
static void do_accept_encoding(
char* t,
QoreHashNode& info) {
3131 while (*a && *a !=
';' && *a !=
',')
3135 l->push(str.release(),
nullptr);
3145 info.
setKeyValue(
"accept-encoding", l.release(), 0);
3148 DLLLOCAL
bool do_accept_charset(
char* t,
QoreHashNode& info) {
3149 bool acceptcharset =
false;
3164 if (*a ==
'u' || *a ==
'U') {
3166 if (*a ==
't' || *a ==
'T') {
3168 if (*a ==
'f' || *a ==
'F') {
3180 }
else if (*a ==
',') {
3184 }
else if (*a ==
';') {
3193 acceptcharset =
true;
3197 ac->concat(t, div - t);
3202 info.
setKeyValue(
"accept-charset", ac.release(), 0);
3203 acceptcharset =
true;
3207 return acceptcharset;
3212 bool* chunked =
nullptr,
const char* headers_raw_key =
"headers-raw") {
3213 bool close = !(flags & CHF_HTTP11);
3215 const char* senc =
nullptr;
3217 bool acceptcharset =
false;
3225 std::string raw_key;
3230 if ((p = strstr(buf,
"\r\n"))) {
3233 }
else if ((p = strchr(buf,
'\n'))) {
3236 }
else if ((p = strchr(buf,
'\r'))) {
3241 char* t = strchr(buf,
':');
3246 while (t && qore_isblank(*t))
3256 if (flags & CHF_PROCESS) {
3257 if (!strcmp(buf,
"connection")) {
3258 if (flags & CHF_HTTP11) {
3259 if (strcasestr(t,
"close"))
3262 if (strcasestr(t,
"keep-alive"))
3265 }
else if (!strcmp(buf,
"content-type")) {
3266 char* a = strcasestr(t,
"charset=");
3269 char* e = strchr(a + 8,
';');
3273 cs.
concat(a + 8, e - a - 8);
3292 }
while (a > t && (*a ==
' ' || *a ==
';'));
3299 ct->concat(t, a - t + 1);
3305 info->
setKeyValue(
"body-content-type", ct.release(),
nullptr);
3311 info->
setKeyValue(
"body-content-type", val->refSelf(),
nullptr);
3314 }
else if (chunked && !strcmp(buf,
"transfer-encoding") && !strcasecmp(t,
"chunked")) {
3317 if (!strcmp(buf,
"accept-charset"))
3318 acceptcharset = do_accept_charset(t, *info);
3319 else if ((flags & CHF_REQUEST) && !strcmp(buf,
"accept-encoding"))
3320 do_accept_encoding(t, *info);
3325 if (raw_hdr && val) {
3326 val_copy = val->realCopy();
3330 hash_assignment_priv ha(*h, buf);
3331 if (!(*ha).isNothing()) {
3333 if ((*ha).getType() ==
NT_LIST) {
3337 l->
push(ha.swap(l),
nullptr);
3339 l->
push(val.release(),
nullptr);
3341 ha.assign(val.release(), 0);
3345 hash_assignment_priv ha(*raw_hdr, raw_key);
3346 if (!(*ha).isNothing()) {
3348 if ((*ha).getType() ==
NT_LIST) {
3352 l->
push(ha.swap(l),
nullptr);
3354 l->
push(val_copy.release(),
nullptr);
3356 ha.assign(val_copy.release(),
nullptr);
3360 if ((flags & CHF_PROCESS)) {
3364 if (info && !acceptcharset)
3371 DLLLOCAL
int recvix(
const char* meth,
int len,
void* targ,
int timeout_ms,
ExceptionSink* xsink) {
3373 if (sock == QORE_INVALID_SOCKET) {
3374 se_not_open(
"Socket", meth, xsink);
3375 return QSE_NOT_OPEN;
3379 se_in_op(
"Socket", meth, xsink);
3382 se_in_op_thread(
"Socket", meth, xsink);
3386 PrivateQoreSocketThroughputHelper th(
this,
false);
3391 qore_offset_t rc = brecv(xsink, meth, buf, len - br, 0, timeout_ms);
3393 do_read_error(rc, meth, timeout_ms, xsink);
3397 memcpy(targ, buf, rc);
3405 do_data_event(QORE_EVENT_SOCKET_DATA_READ, QORE_SOURCE_SOCKET, targ, br);
3411 if (warn_callback_arg) {
3412 warn_callback_arg.
discard(xsink);
3415 warn_queue->deref(xsink);
3416 warn_queue =
nullptr;
3418 tp_warning_bs = 0.0;
3426 if (warning_ms <= 0 && warning_bs <= 0) {
3427 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);
3437 warn_queue->
deref(xsink);
3438 warn_callback_arg.
discard(xsink);
3441 warn_queue = qholder.release();
3442 warn_callback_arg = holder.release();
3443 tl_warning_us = (
int64)warning_ms * 1000;
3444 tp_warning_bs = warning_bs;
3445 tp_us_min = min_ms * 1000;
3448 DLLLOCAL
void getUsageInfo(
QoreHashNode& h, qore_socket_private& s)
const {
3456 h.
setKeyValue(
"bytes_sent", tp_bytes_sent + s.tp_bytes_sent, 0);
3457 h.
setKeyValue(
"bytes_recv", tp_bytes_recv + s.tp_bytes_sent, 0);
3458 h.
setKeyValue(
"us_sent", tp_us_sent + s.tp_us_sent, 0);
3459 h.
setKeyValue(
"us_recv", tp_us_recv + s.tp_us_recv, 0);
3482 DLLLOCAL
void clearStats() {
3489 DLLLOCAL
void doTimeoutWarning(
const char* op,
int64 dt) {
3491 assert(dt > tl_warning_us);
3499 if (warn_callback_arg)
3502 warn_queue->pushAndTakeRef(h);
3505 DLLLOCAL
void doThroughputWarning(
bool send,
int64 bytes,
int64 dt,
double bs) {
3507 assert(bs < tp_warning_bs);
3517 if (warn_callback_arg)
3520 warn_queue->pushAndTakeRef(h);
3523 DLLLOCAL
bool pendingHttpChunkedBody()
const {
3524 return http_exp_chunked_body && sock != QORE_INVALID_SOCKET;
3527 DLLLOCAL
void setSslVerifyMode(
int mode) {
3529 ssl_verify_mode = mode;
3531 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3534 DLLLOCAL
void acceptAllCertificates(
bool accept_all =
true) {
3535 ssl_accept_all_certs = accept_all;
3537 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3542 ssl_err_str->
concat(
"; ");
3543 ssl_err_str->
concat(err_str);
3546 ssl_err_str = err_str;
3551 sock.priv->getUsageInfo(h, *s.priv);
3554 DLLLOCAL
static qore_socket_private*
get(
QoreSocket& sock) {
3558 DLLLOCAL
static const qore_socket_private*
get(
const QoreSocket& sock) {
3562 DLLLOCAL
static void captureRemoteCert(X509_STORE_CTX* x509_ctx);
const qore_type_t NT_BINARY
type value for BinaryNode
Definition: node_types.h:49
DLLEXPORT const char * c_str() const
returns the string's buffer; this data should not be changed
Qore's arbitrary-precision number value type, dynamically-allocated only, reference counted...
Definition: QoreNumberNode.h:51
defines string encoding functions in Qore
Definition: QoreEncoding.h:83
a helper class for getting socket origination information
Definition: QoreSocket.h:73
DLLEXPORT bool empty() const
returns true if the string is empty, false if not
This is the hash or associative list container type in Qore, dynamically allocated only...
Definition: QoreHashNode.h:50
DLLEXPORT const QoreEncoding * QCS_DEFAULT
the default encoding for the Qore library
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 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 int gettid() noexcept
returns the current TID number
const qore_type_t NT_LIST
type value for QoreListNode
Definition: node_types.h:50
DLLEXPORT bool empty() const
returns true if empty
DLLEXPORT char * giveBuffer()
returns the character buffer and leaves the QoreString empty, the caller owns the memory returned (mu...
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:54
const qore_type_t NT_NOTHING
type value for QoreNothingNode
Definition: node_types.h:42
DLLEXPORT int setKeyValue(const char *key, QoreValue value, ExceptionSink *xsink)
sets the value of "key" to "value"
size_t qore_size_t
used for sizes (same range as a pointer)
Definition: common.h:73
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 ...
DLLEXPORT QoreHashNode * hashRefSelf() const
returns "this" with an incremented reference count
DLLLOCAL T * release()
releases the pointer to the caller
Definition: ReferenceHolder.h:91
DLLLOCAL hashdecl addrinfo * getAddrInfo() const
returns the hashdecl addrinfo * being managed (may by 0)
Definition: QoreNet.h:159
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
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...
provides an interface to getaddrinfo
Definition: QoreNet.h:132
DLLEXPORT int push(QoreValue val, ExceptionSink *xsink)
adds a value to the list
const qore_type_t NT_NULL
type value for QoreNullNode
Definition: node_types.h:48
Interface for private data of output streams.
Definition: OutputStream.h:44
DLLEXPORT AbstractQoreNode * refSelf() const
returns "this" with an incremented reference count
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:81
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
virtual void write(const void *ptr, int64 count, ExceptionSink *xsink)=0
Writes bytes to the output stream.
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
static DLLEXPORT const char * getFamilyName(int address_family)
returns the name of the address family as a string (ie AF_INET = "ipv4", etc)
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
DLLEXPORT QoreEncodingManager QEM
the QoreEncodingManager object
DLLEXPORT qore_size_t strlen() const
returns number of bytes in the string (not including the null pointer)
const qore_type_t NT_HASH
type value for QoreHashNode
Definition: node_types.h:51
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'...
virtual DLLLOCAL QoreValue execValue(const QoreListNode *args, ExceptionSink *xsink) const =0
pure virtual function for executing the function reference
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
const qore_type_t NT_STRING
type value for QoreStringNode
Definition: node_types.h:45
provides access to sockets using Qore data structures
Definition: QoreSocket.h:126
virtual DLLEXPORT AbstractQoreNode * realCopy() const =0
returns a copy of the object; the caller owns the reference count
the implementation of Qore's object data type, reference counted, dynamically-allocated only ...
Definition: QoreObject.h:61
DLLEXPORT bool empty() const
returns true if the hash has no members, false if not
DLLEXPORT void clear()
frees any managed memory and sets the size to 0
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:46
const qore_type_t NT_FLOAT
type value for floating-point values (QoreValue only)
Definition: node_types.h:44
DLLEXPORT QoreStringNode * q_strerror(int errnum)
returns the error string as a QoreStringNode
const qore_type_t NT_BOOLEAN
type value for bools (QoreValue only)
Definition: node_types.h:47
static void strtolower(char *str)
convert a string to lower-case in place
Definition: QoreLib.h:267
const qore_type_t NT_INT
type value for integers (QoreValue only)
Definition: node_types.h:43
DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count and calls derefImpl() if there_can_be_only_one is false, otherwise does nothing
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
DLLEXPORT const void * getPtr() const
returns the pointer to the data
intptr_t qore_offset_t
used for offsets that could be negative
Definition: common.h:76
DLLEXPORT void trim(const char *chars=0)
remove leading and trailing whitespace or other characters
base class for resolved call references
Definition: CallReferenceNode.h:105
#define QORE_MIN(a, b)
macro to return the minimum of 2 numbers
Definition: QoreLib.h:535
DLLEXPORT qore_size_t size() const
returns the number of members in the hash, executes in constant time
constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:563
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:47
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, "::1" = "ipv6[::1]")
const qore_type_t NT_NUMBER
type value for QoreNumberNode
Definition: node_types.h:53
DLLEXPORT void setValue(const char *key, QoreValue val, ExceptionSink *xsink)
sets the value of the given member to the given value
DLLEXPORT qore_size_t size() const
returns the number of bytes in the object
DLLEXPORT void clear()
reset string to zero length; memory is not deallocated; string encoding does not change ...
DLLEXPORT qore_size_t size() const
returns number of bytes in the string (not including the null pointer)
holds an object and dereferences it in the destructor
Definition: QoreValue.h:452
DLLEXPORT QoreValue refSelf() const
references the contained value if type == QV_Node, returns itself
DLLEXPORT void append(const void *nptr, qore_size_t size)
resizes the object and appends a copy of the data passed to the object
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values ...
provides a safe and exception-safe way to release and re-acquire locks in Qore, only to be used on th...
Definition: QoreThreadLock.h:187
holds arbitrary binary data
Definition: BinaryNode.h:41
For use on the stack only: iterates through elements of a const QoreListNode.
Definition: QoreListNode.h:566