32 #ifndef _QORE_QORE_SOCKET_PRIVATE_H
33 #define _QORE_QORE_SOCKET_PRIVATE_H
35 #include "qore/AbstractPollState.h"
36 #include "qore/QoreSocket.h"
37 #include "qore/InputStream.h"
38 #include "qore/OutputStream.h"
40 #include "qore/intern/SSLSocketHelper.h"
41 #include "qore/intern/QC_Queue.h"
50 #include <openssl/ssl.h>
51 #include <openssl/err.h>
55 #elif defined HAVE_SYS_SELECT_H
56 #include <sys/select.h>
57 #elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
60 #error no async socket I/O APIs available
63 #ifndef DEFAULT_SOCKET_BUFSIZE
64 #define DEFAULT_SOCKET_BUFSIZE (64 * 1024)
67 #ifndef QORE_MAX_HEADER_SIZE
68 #define QORE_MAX_HEADER_SIZE 16384
71 #define CHF_HTTP11 (1 << 0)
72 #define CHF_PROCESS (1 << 1)
73 #define CHF_REQUEST (1 << 2)
75 #ifndef DEFAULT_SOCKET_MIN_THRESHOLD_BYTES
76 #define DEFAULT_SOCKET_MIN_THRESHOLD_BYTES 1024
79 static constexpr
int SOCK_POLLIN = (1 << 0);
80 static constexpr
int SOCK_POLLOUT = (1 << 1);
81 static constexpr
int SOCK_POLLERR = (1 << 2);
83 DLLLOCAL
void concat_target(
QoreString& str,
const struct sockaddr *addr,
const char* type =
"target");
85 DLLLOCAL
int sock_get_raw_error();
86 DLLLOCAL
int sock_get_error();
87 DLLLOCAL
void qore_socket_error(
ExceptionSink* xsink,
const char* err,
const char* cdesc,
const char* mname =
nullptr,
88 const char* host =
nullptr,
const char* svc =
nullptr,
const struct sockaddr *addr =
nullptr);
89 DLLLOCAL
void qore_socket_error_intern(
int rc,
ExceptionSink* xsink,
const char* err,
const char* cdesc,
90 const char* mname =
nullptr,
const char* host =
nullptr,
const char* svc =
nullptr,
91 const struct sockaddr* addr =
nullptr);
92 DLLLOCAL
void se_in_op(
const char* cname,
const char* meth,
ExceptionSink* xsink);
93 DLLLOCAL
void se_in_op_thread(
const char* cname,
const char* meth,
ExceptionSink* xsink);
94 DLLLOCAL
void se_not_open(
const char* cname,
const char* meth,
ExceptionSink* xsink,
const char* extra =
nullptr);
95 DLLLOCAL
void se_timeout(
const char* cname,
const char* meth,
int timeout_ms,
ExceptionSink* xsink);
96 DLLLOCAL
void se_closed(
const char* cname,
const char* mname,
ExceptionSink* xsink);
99 #define GETSOCKOPT_ARG_4 char*
100 #define SETSOCKOPT_ARG_4 const char*
101 #define SHUTDOWN_ARG SD_BOTH
102 #define QORE_INVALID_SOCKET ((int)INVALID_SOCKET)
103 #define QORE_SOCKET_ERROR SOCKET_ERROR
104 DLLLOCAL
int check_windows_rc(
int rc);
107 #define ECONNRESET WSAECONNRESET
112 #define GETSOCKOPT_ARG_4 void*
113 #define SETSOCKOPT_ARG_4 void*
114 #define SHUTDOWN_ARG SHUT_RDWR
115 #define QORE_INVALID_SOCKET -1
116 #define QORE_SOCKET_ERROR -1
119 template <
typename T>
120 class PrivateDataListHolder {
122 DLLLOCAL PrivateDataListHolder(
ExceptionSink* xsink) : xsink(xsink) {
125 DLLLOCAL ~PrivateDataListHolder() {
126 for (
auto& i : pd_vec)
134 pd_vec.push_back(pd);
139 typedef std::vector<T*> pd_vec_t;
144 hashdecl qore_socketsource_private {
148 DLLLOCAL qore_socketsource_private() : address(0), hostname(0) {
151 DLLLOCAL ~qore_socketsource_private() {
152 if (address) address->deref();
153 if (hostname) hostname->deref();
161 DLLLOCAL
void setAddress(
const char* addr) {
166 DLLLOCAL
void setHostName(
const char* host) {
173 o->
setValue(
"source", address, xsink);
178 o->
setValue(
"source_host", hostname, xsink);
184 class OptionalNonBlockingHelper {
186 qore_socket_private& sock;
190 DLLLOCAL OptionalNonBlockingHelper(qore_socket_private& s,
bool n_set,
ExceptionSink* xs);
191 DLLLOCAL ~OptionalNonBlockingHelper();
194 class PrivateQoreSocketTimeoutBase {
196 hashdecl qore_socket_private* sock;
200 DLLLOCAL PrivateQoreSocketTimeoutBase(qore_socket_private* s) : sock(s), start(sock ? q_clock_getmicros() : 0) {
204 class PrivateQoreSocketTimeoutHelper :
public PrivateQoreSocketTimeoutBase {
208 DLLLOCAL PrivateQoreSocketTimeoutHelper(qore_socket_private* s,
const char* op);
209 DLLLOCAL ~PrivateQoreSocketTimeoutHelper();
212 class PrivateQoreSocketThroughputHelper :
public PrivateQoreSocketTimeoutBase {
216 DLLLOCAL PrivateQoreSocketThroughputHelper(qore_socket_private* s,
bool snd);
217 DLLLOCAL ~PrivateQoreSocketThroughputHelper();
219 DLLLOCAL
void finalize(
int64 bytes);
222 hashdecl qore_socket_private;
224 hashdecl qore_socket_op_helper {
226 qore_socket_private* s;
229 DLLLOCAL qore_socket_op_helper(qore_socket_private* sock);
230 DLLLOCAL ~qore_socket_op_helper();
233 class SSLSocketHelperHelper {
235 qore_socket_private* s;
236 SSLSocketHelper* ssl;
237 bool context_saved =
false;
240 DLLLOCAL SSLSocketHelperHelper(qore_socket_private* sock,
bool set_thread_context =
false);
242 DLLLOCAL ~SSLSocketHelperHelper();
244 DLLLOCAL
void error();
247 constexpr
int SCIPS_CONNECT = 0;
248 constexpr
int SCIPS_CHECK_CONNECT = 1;
250 class SocketConnectInetPollState :
public AbstractPollState {
252 DLLLOCAL SocketConnectInetPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* host,
253 const char* service,
int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0);
265 qore_socket_private* sock;
266 std::string host, service;
267 hashdecl addrinfo* p =
nullptr;
269 int state = SCIPS_CONNECT;
284 class SocketConnectUnixPollState :
public AbstractPollState {
286 DLLLOCAL SocketConnectUnixPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* name,
287 int type = SOCK_STREAM,
int protocol = 0);
298 qore_socket_private* sock;
300 hashdecl sockaddr_un addr;
301 int state = SCIPS_CONNECT;
310 class SocketConnectSslPollState :
public AbstractPollState {
312 DLLLOCAL SocketConnectSslPollState(
ExceptionSink* xsink, qore_socket_private* sock, X509* cert, EVP_PKEY* pkey);
323 qore_socket_private* sock;
330 class SocketAcceptPollState :
public AbstractPollState {
332 DLLLOCAL SocketAcceptPollState(
ExceptionSink* xsink, qore_socket_private* sock);
334 qore_socket_private* sock;
337 class SocketAcceptSslPollState :
public AbstractPollState {
338 DLLLOCAL SocketAcceptSslPollState(
ExceptionSink* xsink, qore_socket_private* sock, X509* cert, EVP_PKEY* pkey)
341 SSLSocketHelperHelper sshh(sock,
true);
343 sock->do_start_ssl_event();
345 if (rc = sock->ssl->setServer(
"acceptSSL", sock->sock, cert, pkey, xsink)) {
351 ssl->startAccept(xsink);
356 class SocketSendPollState :
public AbstractPollState {
358 DLLLOCAL SocketSendPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* data,
size_t size);
369 qore_socket_private* sock;
375 class SocketRecvPollState :
public AbstractPollState {
377 DLLLOCAL SocketRecvPollState(
ExceptionSink* xsink, qore_socket_private* sock,
size_t size);
388 DLLLOCAL
virtual QoreValue takeOutput() {
395 qore_socket_private* sock;
401 class SocketRecvUntilBytesPollState :
public AbstractPollState {
403 DLLLOCAL SocketRecvUntilBytesPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* bytes,
415 DLLLOCAL
virtual QoreValue takeOutput() {
416 size_t len = bin->size();
423 qore_socket_private* sock;
434 hashdecl qore_socket_private {
435 friend class PrivateQoreSocketTimeoutHelper;
436 friend class PrivateQoreSocketThroughputHelper;
437 friend class SocketConnectInetPollState;
440 static thread_local qore_socket_private* current_socket;
442 int sock, sfamily, port, stype, sprot;
445 int64 connection_id = 0;
449 std::string socketname;
451 std::string client_target;
452 SSLSocketHelper* ssl =
nullptr;
453 Queue* event_queue =
nullptr,
454 * warn_queue =
nullptr;
457 std::string assume_http_encoding =
"ISO-8859-1";
460 char rbuf[DEFAULT_SOCKET_BUFSIZE];
466 int64 tl_warning_us = 0;
467 double tp_warning_bs = 0;
468 int64 tp_bytes_sent = 0,
480 http_exp_chunked_body =
false,
481 ssl_accept_all_certs =
false,
482 ssl_capture_remote_cert =
false,
485 ssl_verify_mode = SSL_VERIFY_NONE;
493 DLLLOCAL qore_socket_private(
int n_sock = QORE_INVALID_SOCKET,
int n_sfamily = AF_UNSPEC,
495 sock(n_sock), sfamily(n_sfamily), port(-1), stype(n_stype), sprot(n_prot), enc(n_enc) {
498 DLLLOCAL ~qore_socket_private() {
502 assert(!event_queue);
506 DLLLOCAL
bool isOpen() {
507 return sock != QORE_INVALID_SOCKET;
510 DLLLOCAL
int close() {
511 int rc = close_internal();
514 if (http_exp_chunked_body)
515 http_exp_chunked_body =
false;
523 DLLLOCAL
int close_and_reset() {
524 assert(sock != QORE_INVALID_SOCKET);
528 rc = ::closesocket(sock);
533 if (!rc || sock_get_error() != EINTR)
537 sock = QORE_INVALID_SOCKET;
547 client_target.clear();
551 DLLLOCAL
int close_internal() {
554 ssl_err_str->deref();
555 ssl_err_str =
nullptr;
558 remote_cert->
deref(
nullptr);
559 remote_cert =
nullptr;
569 if (!socketname.empty()) {
571 unlink(socketname.c_str());
579 return close_and_reset();
585 DLLLOCAL
void setAssumedEncoding(
const char* str) {
586 assume_http_encoding = str;
589 DLLLOCAL
const char* getAssumedEncoding()
const {
590 return assume_http_encoding.c_str();
593 DLLLOCAL
int getSendTimeout()
const {
596 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
599 int size =
sizeof(
hashdecl timeval);
601 socklen_t size =
sizeof(
hashdecl timeval);
604 if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
607 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
610 DLLLOCAL
int getRecvTimeout()
const {
613 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
616 int size =
sizeof(
hashdecl timeval);
618 socklen_t size =
sizeof(
hashdecl timeval);
621 if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
624 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
627 DLLLOCAL
int getPort() {
629 if (sock == QORE_INVALID_SOCKET || (sfamily != AF_INET && sfamily != AF_INET6) || port > 0)
633 hashdecl sockaddr_storage addr;
634 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
636 int size =
sizeof addr;
638 socklen_t size =
sizeof addr;
641 if (getsockname(sock, (
struct sockaddr *)&addr, (socklen_t *)&size) < 0)
644 port = q_get_port_from_addr((
const struct sockaddr *)&addr);
649 switch (v.getType()) {
654 hdr.
sprintf(
"%s: " QLLD
"\r\n", key, v.getAsBigInt());
658 size_t offset = hdr.
size();
659 hdr.
sprintf(
"%f\r\n", v.getAsFloat());
663 q_fix_decimal(&hdr, offset);
672 hdr.
sprintf(
"%s: %d\r\n", key, (
int)v.getAsBool());
680 DLLLOCAL
static void do_headers(
QoreString& hdr,
const QoreHashNode* headers,
size_t size,
bool addsize =
true) {
688 const char* key = hi.getKey();
689 if (addsize && !strcasecmp(key,
"transfer-encoding"))
691 if ((addsize || size) && !strcasecmp(key,
"content-length")) {
698 do_header(key, hdr, li.getValue());
700 do_header(key, hdr, v);
704 if (size || addsize) {
705 hdr.
sprintf(
"Content-Length: " QLLD
"\r\n", size);
712 DLLLOCAL
int listen(
int backlog = 20) {
713 if (sock == QORE_INVALID_SOCKET)
718 if (::listen(sock, backlog)) {
725 return ::listen(sock, backlog);
729 DLLLOCAL
int accept_intern(
ExceptionSink* xsink,
struct sockaddr *addr, socklen_t *size,
int timeout_ms = -1) {
733 if (timeout_ms >= 0 && !isDataAvailable(timeout_ms,
"accept", xsink)) {
740 int rc = ::accept(sock, addr, size);
741 if (rc != QORE_INVALID_SOCKET)
745 if (sock_get_error() == EINTR)
748 qore_socket_error(xsink,
"SOCKET-ACCEPT-ERROR",
"error in accept()", 0, 0, 0, addr);
756 if (sock == QORE_INVALID_SOCKET) {
757 xsink->
raiseException(
"SOCKET-NOT-OPEN",
"socket must be opened, bound, and in a listening state before "
758 "new connections can be accepted");
763 se_in_op(
"Socket",
"accept", xsink);
766 se_in_op_thread(
"Socket",
"accept", xsink);
767 return QSE_IN_OP_THREAD;
771 if (sfamily == AF_UNIX) {
773 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"UNIX sockets are not available under Windows");
776 hashdecl sockaddr_un addr_un;
778 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
781 int size =
sizeof(
hashdecl sockaddr_un);
783 socklen_t size =
sizeof(
hashdecl sockaddr_un);
785 rc = accept_intern(xsink, (
struct sockaddr *)&addr_un, (socklen_t *)&size, timeout_ms);
788 if (rc >= 0 && source) {
790 addr->
sprintf(
"UNIX socket: %s", socketname.c_str());
791 source->priv->setAddress(addr);
792 source->priv->setHostName(
"localhost");
795 }
else if (sfamily == AF_INET || sfamily == AF_INET6) {
796 hashdecl sockaddr_storage addr_in;
797 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
800 int size =
sizeof(addr_in);
802 socklen_t size =
sizeof(addr_in);
805 rc = accept_intern(xsink, (
struct sockaddr *)&addr_in, (socklen_t *)&size, timeout_ms);
808 if (rc >= 0 && source) {
809 char host[NI_MAXHOST + 1];
810 char service[NI_MAXSERV + 1];
812 if (!getnameinfo((
struct sockaddr *)&addr_in, qore_get_in_len((
struct sockaddr *)&addr_in), host,
sizeof(host), service,
sizeof(service), NI_NUMERICSERV)) {
813 source->priv->setHostName(host);
817 char ifname[INET6_ADDRSTRLEN];
818 if (inet_ntop(addr_in.ss_family, qore_get_in_addr((
struct sockaddr *)&addr_in), ifname,
sizeof(ifname))) {
820 source->priv->setAddress(ifname);
825 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"do not know how to accept connections with address family %d", sfamily);
831 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_SOCKET)
const {
850 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
853 event_queue->deref(xsink);
854 event_queue =
nullptr;
857 warn_queue->deref(xsink);
858 warn_queue =
nullptr;
859 if (warn_callback_arg) {
860 warn_callback_arg.
discard(xsink);
861 warn_callback_arg.clear();
871 event_queue->deref(xsink);
875 event_data = with_data;
878 DLLLOCAL
void do_start_ssl_event() {
880 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_START_SSL));
884 DLLLOCAL
void do_ssl_established_event() {
889 event_queue->pushAndTakeRef(h);
893 DLLLOCAL
void do_connect_event(
int af,
const struct sockaddr* addr,
const char* target,
const char* service =
nullptr,
int prt = -1) {
902 q_af_to_hash(af, *h,
nullptr);
908 event_queue->pushAndTakeRef(h);
912 DLLLOCAL
void do_connected_event() {
914 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CONNECTED));
918 DLLLOCAL
void do_data_event_intern(
int event,
int source,
const QoreStringNode& str)
const {
919 assert(event_queue && event_data && str.
size());
922 event_queue->pushAndTakeRef(h.release());
925 DLLLOCAL
void do_data_event(
int event,
int source,
const QoreStringNode& str)
const {
926 if (event_queue && event_data && str.
size()) {
927 do_data_event_intern(event, source, str);
931 DLLLOCAL
void do_data_event(
int event,
int source,
const BinaryNode& b)
const {
932 if (event_queue && event_data && b.
size()) {
935 event_queue->pushAndTakeRef(h.release());
939 DLLLOCAL
void do_data_event(
int event,
int source,
const void* data,
size_t size)
const {
940 if (event_queue && event_data && size) {
945 event_queue->pushAndTakeRef(h.release());
949 DLLLOCAL
void do_header_event(
int event,
int source,
const QoreHashNode& hdr)
const {
950 if (event_queue && event_data && !hdr.
empty()) {
953 event_queue->pushAndTakeRef(h.release());
957 DLLLOCAL
void do_chunked_read(
int event,
size_t bytes,
size_t total_read,
int source) {
960 if (event == QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED)
965 event_queue->pushAndTakeRef(h);
969 DLLLOCAL
void do_read_http_header(
int event,
const QoreHashNode* headers,
int source) {
973 event_queue->pushAndTakeRef(h);
977 DLLLOCAL
void do_send_http_message_event(
const QoreString& str,
const QoreHashNode* headers,
int source) {
979 QoreHashNode* h = getEvent(QORE_EVENT_HTTP_SEND_MESSAGE, source);
983 event_queue->pushAndTakeRef(h);
987 DLLLOCAL
void do_close_event() {
989 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
993 DLLLOCAL
void do_read_event(
size_t bytes_read,
size_t total_read,
size_t bufsize = 0,
int source = QORE_SOURCE_SOCKET) {
996 QoreHashNode* h = getEvent(QORE_EVENT_PACKET_READ, source);
1001 h->
setKeyValue(
"total_to_read", bufsize,
nullptr);
1002 event_queue->pushAndTakeRef(h);
1006 DLLLOCAL
void do_send_event(
int bytes_sent,
int total_sent,
int bufsize) {
1011 h->
setKeyValue(
"total_sent", total_sent,
nullptr);
1012 h->
setKeyValue(
"total_to_send", bufsize,
nullptr);
1013 event_queue->pushAndTakeRef(h);
1017 DLLLOCAL
void do_resolve_event(
const char* host,
const char* service = 0) {
1020 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_LOOKUP);
1025 event_queue->pushAndTakeRef(h);
1029 DLLLOCAL
void do_resolved_event(
const struct sockaddr* addr) {
1032 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_RESOLVED);
1038 int prt = q_get_port_from_addr(addr);
1041 q_af_to_hash(addr->sa_family, *h,
nullptr);
1042 event_queue->pushAndTakeRef(h);
1046 DLLLOCAL
int64 getObjectIDForEvents()
const {
1050 DLLLOCAL
int connectUNIX(
const char* p,
int sock_type,
int protocol,
ExceptionSink* xsink) {
1053 QORE_TRACE(
"connectUNIX()");
1056 xsink->
raiseException(
"SOCKET-CONNECTUNIX-ERROR",
"UNIX sockets are not available under Windows");
1062 printd(5,
"qore_socket_private::connectUNIX(%s)\n", p);
1064 hashdecl sockaddr_un addr;
1066 addr.sun_family = AF_UNIX;
1068 strncpy(addr.sun_path, p,
sizeof(addr.sun_path) - 1);
1069 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1070 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_SOCKET_ERROR) {
1071 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"error connecting to UNIX socket: '%s'", p);
1075 do_connect_event(AF_UNIX, (sockaddr*)&addr, p);
1077 if (!::connect(sock, (
const sockaddr *)&addr,
sizeof(
struct sockaddr_un)))
1081 if (sock_get_error() == EINTR)
1087 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, p);
1093 socketname = addr.sun_path;
1096 do_connected_event();
1108 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
const char* cname,
const char* mname,
1111 assert(read || write);
1112 if (sock == QORE_INVALID_SOCKET) {
1113 se_not_open(cname, mname, xsink,
"asyncIoWait");
1117 return asyncIoWait(timeout_ms, read, write, xsink);
1120 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
ExceptionSink* xsink)
const {
1122 #if defined HAVE_POLL
1123 return poll_intern(xsink, timeout_ms, read, write);
1124 #elif defined HAVE_SELECT
1125 return select_intern(xsink, timeout_ms, read, write);
1127 #error no async socket operations supported
1131 #if defined HAVE_POLL
1132 DLLLOCAL
int poll_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1139 pollfd fds = {sock, arg, 0};
1141 rc = ::poll(&fds, 1, timeout_ms);
1142 if (rc == -1 && errno == EINTR)
1147 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"poll(2) returned an error");
1148 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
1153 #elif defined HAVE_SELECT
1154 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1155 bool aborted =
false;
1156 int rc = select_intern(xsink, timeout_ms, read, write, aborted);
1157 if (rc != QORE_SOCKET_ERROR && aborted)
1162 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write,
bool& aborted)
const {
1169 if (sock >= FD_SETSIZE) {
1170 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);
1174 hashdecl timeval tv;
1185 tv.tv_sec = timeout_ms / 1000;
1186 tv.tv_usec = (timeout_ms % 1000) * 1000;
1188 fd_set* readfd = read ? &sfs : 0;
1189 fd_set* writefd = write ? &sfs : 0;
1191 rc = select(sock + 1, readfd, writefd, &err, &tv);
1193 if (rc != QORE_SOCKET_ERROR) {
1194 if (FD_ISSET(sock, &err))
1198 if (sock_get_error() != EINTR)
1201 if (rc == QORE_SOCKET_ERROR) {
1204 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"select(2) returned an error");
1211 DLLLOCAL
bool tryReadSocketData(
const char* mname,
ExceptionSink* xsink) {
1216 return asyncIoWait(0,
true,
false,
"Socket", mname, xsink);
1220 int rc = ssl->doSSLRW(xsink, mname, rbuf, 1, 0, PEEK,
false);
1221 if (*xsink || (rc == QSE_TIMEOUT)) {
1224 return rc > 0 ? true :
false;
1227 DLLLOCAL
bool isSocketDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1228 return asyncIoWait(timeout_ms,
true,
false,
"Socket", mname, xsink);
1231 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1234 return isSocketDataAvailable(timeout_ms, mname, xsink);
1237 DLLLOCAL
bool isWriteFinished(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1238 return asyncIoWait(timeout_ms,
false,
true,
"Socket", mname, xsink);
1241 DLLLOCAL
int close_and_exit() {
1242 if (sock != QORE_INVALID_SOCKET)
1247 DLLLOCAL
int connectINETTimeout(
int timeout_ms,
const struct sockaddr* ai_addr,
size_t ai_addrlen,
1250 PrivateQoreSocketTimeoutHelper toh(
this,
"connect");
1253 if (!::connect(sock, ai_addr, ai_addrlen))
1257 if (sock_get_error() != EAGAIN) {
1258 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1266 if (errno != EINPROGRESS)
1275 bool aborted =
false;
1276 int rc = select_intern(xsink, timeout_ms,
false,
true, aborted);
1283 if (rc != QORE_SOCKET_ERROR && aborted) {
1284 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1288 int rc = asyncIoWait(timeout_ms,
false,
true,
"Socket",
"connectINETTimeout", xsink);
1294 if (rc == QORE_SOCKET_ERROR && sock_get_error() != EINTR) {
1296 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in asyncIoWait() with "
1297 "Socket::connect() with timeout", 0, 0, 0, ai_addr);
1299 }
else if (rc > 0) {
1300 return checkConnected(xsink,
nullptr, ai_addr, only_timeout);
1304 concat_target(*(*desc), ai_addr);
1314 DLLLOCAL
int checkConnected(
ExceptionSink* xsink,
const char* hostsvc,
const struct sockaddr* ai_addr =
nullptr,
1315 bool only_timeout =
false) {
1319 socklen_t lon =
sizeof(int);
1322 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (GETSOCKOPT_ARG_4)(&val), &lon) == QORE_SOCKET_ERROR) {
1323 if (!only_timeout) {
1324 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
nullptr,
1335 qore_socket_error_intern(val, xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
1344 DLLLOCAL
void confirmConnected(
const char* host) {
1345 do_connected_event();
1349 client_target = host;
1353 DLLLOCAL
int sock_errno_err(
const char* err,
const char* desc,
ExceptionSink* xsink) {
1354 sock = QORE_INVALID_SOCKET;
1355 qore_socket_error(xsink, err, desc);
1359 DLLLOCAL
int set_non_blocking(
bool non_blocking,
ExceptionSink* xsink) {
1362 if (sock == QORE_INVALID_SOCKET) {
1363 assert(!xsink || *xsink);
1368 u_long mode = non_blocking ? 1 : 0;
1369 int rc = ioctlsocket(sock, FIONBIO, &mode);
1370 if (check_windows_rc(rc)) {
1371 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in ioctlsocket(FIONBIO)", xsink);
1377 if ((arg = fcntl(sock, F_GETFL, 0)) < 0) {
1378 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() getting socket descriptor status "
1388 if (fcntl(sock, F_SETFL, arg) < 0) {
1389 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() setting socket descriptor status "
1398 DLLLOCAL
int connectINET(
const char* host,
const char* service,
int timeout_ms,
ExceptionSink* xsink,
1399 int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0) {
1401 family = q_get_af(family);
1402 type = q_get_sock_type(type);
1404 QORE_TRACE(
"qore_socket_private::connectINET()");
1409 printd(5,
"qore_socket_private::connectINET(%s:%s, %dms)\n", host, service, timeout_ms);
1411 do_resolve_event(host, service);
1414 if (ai.
getInfo(xsink, host, service, family, 0, type, protocol))
1421 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1422 do_resolved_event(p->ai_addr);
1424 int prt = q_get_port_from_addr(aip->ai_addr);
1426 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1427 if (!connectINETIntern(host, service, p->ai_family, p->ai_addr, p->ai_addrlen, p->ai_socktype,
1428 p->ai_protocol, prt, timeout_ms, xsink,
true)) {
1437 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1442 DLLLOCAL
int connectINETIntern(
const char* host,
const char* service,
int ai_family,
struct sockaddr* ai_addr,
1443 size_t ai_addrlen,
int ai_socktype,
int ai_protocol,
int prt,
int timeout_ms,
ExceptionSink* xsink,
1444 bool only_timeout =
false) {
1446 printd(5,
"qore_socket_private::connectINETIntern() host: %s service: %s family: %d timeout_ms: %d\n", host,
1447 service, ai_family, timeout_ms);
1448 if ((sock = socket(ai_family, ai_socktype, ai_protocol)) == QORE_INVALID_SOCKET) {
1449 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"cannot establish a connection to %s:%s", host,
1460 if (timeout_ms >= 0) {
1462 if (set_non_blocking(
true, xsink))
1463 return close_and_exit();
1465 do_connect_event(ai_family, ai_addr, host, service, prt);
1467 rc = connectINETTimeout(timeout_ms, ai_addr, ai_addrlen, xsink, only_timeout);
1471 if (set_non_blocking(
false, xsink))
1472 return close_and_exit();
1474 do_connect_event(ai_family, ai_addr, host, service, prt);
1477 rc = ::connect(sock, ai_addr, ai_addrlen);
1480 if (!rc || sock_get_error() != EINTR)
1486 if (!only_timeout || errno == ETIMEDOUT)
1487 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1489 return close_and_exit();
1492 sfamily = ai_family;
1493 stype = ai_socktype;
1494 sprot = ai_protocol;
1499 confirmConnected(host);
1503 DLLLOCAL
int upgradeClientToSSLIntern(
const char* mname,
const char* sni_target_host, X509* cert, EVP_PKEY* pkey,
1506 SSLSocketHelperHelper sshh(
this,
true);
1509 do_start_ssl_event();
1511 if (!sni_target_host && !client_target.empty()) {
1512 sni_target_host = client_target.c_str();
1514 if ((rc = ssl->setClient(mname, sni_target_host, sock, cert, pkey, xsink)) || ssl->connect(mname, timeout_ms,
1517 return rc ? rc : -1;
1519 do_ssl_established_event();
1524 DLLLOCAL
int upgradeServerToSSLIntern(
const char* mname, X509* cert, EVP_PKEY* pkey,
int timeout_ms,
1528 SSLSocketHelperHelper sshh(
this,
true);
1530 do_start_ssl_event();
1531 if (ssl->setServer(mname, sock, cert, pkey, xsink) || ssl->accept(mname, timeout_ms, xsink)) {
1535 do_ssl_established_event();
1541 DLLLOCAL
int openUNIX(
int sock_type = SOCK_STREAM,
int protocol = 0) {
1542 if (sock != QORE_INVALID_SOCKET)
1545 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_INVALID_SOCKET) {
1557 DLLLOCAL
int openINET(
int family = AF_INET,
int sock_type = SOCK_STREAM,
int protocol = 0) {
1558 if (sock != QORE_INVALID_SOCKET)
1561 if ((sock = socket(family, sock_type, protocol)) == QORE_INVALID_SOCKET)
1571 DLLLOCAL
int reuse(
int opt) {
1573 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_ARG_4)&opt,
sizeof(
int));
1577 DLLLOCAL
int bindIntern(
struct sockaddr* ai_addr,
size_t ai_addrlen,
int prt,
bool reuseaddr,
ExceptionSink* xsink = 0) {
1580 if ((::bind(sock, ai_addr, ai_addrlen)) == QORE_SOCKET_ERROR) {
1582 qore_socket_error(xsink,
"SOCKET-BIND-ERROR",
"error in bind()", 0, 0, 0, ai_addr);
1592 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1594 int len = ai_addrlen;
1596 socklen_t len = ai_addrlen;
1599 if (getsockname(sock, ai_addr, &len))
1602 port = q_get_port_from_addr(ai_addr);
1608 DLLLOCAL
int bindUNIX(
ExceptionSink* xsink,
const char* name,
int socktype = SOCK_STREAM,
int protocol = 0) {
1611 xsink->
raiseException(
"SOCKET-BINDUNIX-ERROR",
"UNIX sockets are not available under Windows");
1617 if (openUNIX(socktype, protocol)) {
1618 xsink->
raiseErrnoException(
"SOCKET-BIND-ERROR", errno,
"error opening UNIX socket ('%s') for bind", name);
1622 hashdecl sockaddr_un addr;
1623 addr.sun_family = AF_UNIX;
1625 strncpy(addr.sun_path, name,
sizeof(addr.sun_path) - 1);
1626 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1628 if (bindIntern((sockaddr*)&addr,
sizeof(
struct sockaddr_un), -1,
false, xsink))
1632 socketname = addr.sun_path;
1639 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) {
1641 family = q_get_af(family);
1642 socktype = q_get_sock_type(socktype);
1647 do_resolve_event(name, service);
1648 if (ai.
getInfo(xsink, name, service, family, AI_PASSIVE, socktype, protocol))
1654 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1655 do_resolved_event(p->ai_addr);
1658 if (openINET(aip->ai_family, aip->ai_socktype, protocol)) {
1659 qore_socket_error(xsink,
"SOCKET-BINDINET-ERROR",
"error opening socket for bind", 0, name, service);
1663 int prt = q_get_port_from_addr(aip->ai_addr);
1667 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1668 if (!bindIntern(p->ai_addr, p->ai_addrlen, prt, reuseaddr)) {
1673 en = sock_get_raw_error();
1678 qore_socket_error_intern(en, xsink,
"SOCKET-BIND-ERROR",
"error binding on socket", 0, name, service);
1685 if (sock == QORE_INVALID_SOCKET) {
1686 se_not_open(
"Socket",
"getPeerInfo", xsink);
1690 hashdecl sockaddr_storage addr;
1691 socklen_t len =
sizeof addr;
1692 if (getpeername(sock, (
struct sockaddr*)&addr, &len)) {
1693 qore_socket_error(xsink,
"SOCKET-GETPEERINFO-ERROR",
"error in getpeername()");
1697 return getAddrInfo(addr, len, host_lookup);
1703 if (sock == QORE_INVALID_SOCKET) {
1704 se_not_open(
"Socket",
"getSocketInfo", xsink);
1708 hashdecl sockaddr_storage addr;
1709 #if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1711 int len =
sizeof addr;
1713 socklen_t len =
sizeof addr;
1716 if (getsockname(sock, (
struct sockaddr*)&addr, &len)) {
1717 qore_socket_error(xsink,
"SOCKET-GETSOCKETINFO-ERROR",
"error in getsockname()");
1721 return getAddrInfo(addr, len, host_lookup);
1724 DLLLOCAL
QoreHashNode* getAddrInfo(
const struct sockaddr_storage& addr, socklen_t len,
bool host_lookup =
true)
const {
1727 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1729 char host[NI_MAXHOST + 1];
1731 if (!getnameinfo((
struct sockaddr*)&addr, qore_get_in_len((
struct sockaddr*)&addr), host,
sizeof(host), 0, 0, 0)) {
1739 char ifname[INET6_ADDRSTRLEN];
1740 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr*)&addr), ifname,
sizeof(ifname))) {
1747 if (addr.ss_family == AF_INET) {
1748 hashdecl sockaddr_in* s = (
hashdecl sockaddr_in*)&addr;
1749 tport = ntohs(s->sin_port);
1751 hashdecl sockaddr_in6* s = (
hashdecl sockaddr_in6*)&addr;
1752 tport = ntohs(s->sin6_port);
1758 else if (addr.ss_family == AF_UNIX) {
1759 assert(!socketname.empty());
1775 hashdecl sockaddr_storage addr;
1777 socklen_t len =
sizeof addr;
1778 if (getpeername(sock, (
struct sockaddr*)&addr, &len))
1781 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1783 char ifname[INET6_ADDRSTRLEN];
1784 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr *)&addr), ifname,
sizeof(ifname))) {
1789 char host[NI_MAXHOST + 1];
1790 if (!getnameinfo((
struct sockaddr *)&addr, qore_get_in_len((
struct sockaddr *)&addr), host,
sizeof(host), 0, 0, 0))
1794 else if (addr.ss_family == AF_UNIX) {
1796 hashdecl sockaddr_un *addr_un = (
hashdecl sockaddr_un *)&addr;
1797 astr->
sprintf(
"UNIX socket: %s", addr_un->sun_path);
1810 DLLLOCAL
int readByteFromBuffer(
char& output) {
1812 assert(sock != QORE_INVALID_SOCKET);
1819 output = *(rbuf + bufoffset);
1832 int timeout,
bool do_event =
true) {
1835 assert(sock != QORE_INVALID_SOCKET);
1840 buf = rbuf + bufoffset;
1858 if (timeout != -1 && !isDataAvailable(timeout, meth, xsink)) {
1861 se_timeout(
"Socket", meth, timeout, xsink);
1870 rc = ::recv(sock, rbuf, DEFAULT_SOCKET_BUFSIZE, flags);
1871 if (rc == QORE_SOCKET_ERROR) {
1876 if (errno == ECONNRESET) {
1877 se_closed(
"Socket", meth, xsink);
1881 qore_socket_error(xsink,
"SOCKET-RECV-ERROR",
"error in recv()", meth);
1890 rc = ssl->read(meth, rbuf, DEFAULT_SOCKET_BUFSIZE, timeout, xsink);
1905 do_read_event(rc, rc);
1919 bool exit_early =
false) {
1922 if (sock == QORE_INVALID_SOCKET) {
1923 se_not_open(
"Socket", meth, xsink,
"readHTTPData");
1928 PrivateQoreSocketThroughputHelper th(
this,
false);
1943 rc = brecv(xsink, meth, buf, 1, 0, timeout,
false);
1951 se_closed(
"Socket", meth, xsink);
1953 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");
1959 if (++count == QORE_MAX_HEADER_SIZE) {
1960 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"header size cannot exceed " QSD
" bytes", count);
1971 if (exit_early && hdr->
empty())
1978 }
else if (c ==
'\r') {
1993 case 0: hdr->concat(
'\r');
break;
1994 case 1: hdr->concat(
"\r\n");
break;
1995 case 2: hdr->concat(
"\r\n\r");
break;
1996 case 3: hdr->concat(
'\n');
break;
2006 th.finalize(hdr->
size());
2008 return hdr.release();
2013 if (sock == QORE_INVALID_SOCKET) {
2014 se_not_open(
"Socket",
"recv", xsink,
"recv");
2020 se_in_op(
"Socket",
"recv", xsink);
2023 se_in_op_thread(
"Socket",
"recv", xsink);
2027 PrivateQoreSocketThroughputHelper th(
this,
false);
2029 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2036 rc = brecv(xsink,
"recv", buf, bs, 0, timeout,
false);
2039 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));
2047 do_read_event(rc, str->
size(), bufsize, source);
2051 if (str->
size() >= (
size_t)bufsize)
2053 if ((bufsize - str->
size()) < bs)
2054 bs = bufsize - str->
size();
2058 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");
2064 th.finalize(str->
size());
2071 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2073 return str.release();
2078 if (sock == QORE_INVALID_SOCKET) {
2079 se_not_open(
"Socket",
"recv", xsink,
"recvAll");
2085 se_in_op(
"Socket",
"recv", xsink);
2088 se_in_op_thread(
"Socket",
"recv", xsink);
2092 PrivateQoreSocketThroughputHelper th(
this,
false);
2098 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2105 do_read_event(rc, rc);
2108 if (isDataAvailable(0,
"recv", xsink)) {
2110 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
2116 th.finalize(str->
size());
2122 do_read_event(rc, str->
size());
2123 }
while (isDataAvailable(0,
"recv", xsink));
2126 th.finalize(str->
size());
2134 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2136 return str.release();
2143 if (sock == QORE_INVALID_SOCKET) {
2144 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinary");
2150 se_in_op(
"Socket",
"recvBinary", xsink);
2153 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2157 PrivateQoreSocketThroughputHelper th(
this,
false);
2159 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2165 rc = brecv(xsink,
"recvBinary", buf, bs, 0, timeout);
2172 if (b->
size() >= (
size_t)bufsize)
2174 if ((bufsize - b->
size()) < bs)
2175 bs = bufsize - b->
size();
2179 th.finalize(b->
size());
2189 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2191 printd(5,
"qore_socket_private::recvBinary() received " QSD
" byte(s), bufsize=" QSD
", blen=" QSD
"\n", b->
size(), bufsize, b->
size());
2197 if (sock == QORE_INVALID_SOCKET) {
2198 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinaryAll");
2204 se_in_op(
"Socket",
"recvBinary", xsink);
2207 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2211 PrivateQoreSocketThroughputHelper th(
this,
false);
2218 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2225 do_read_event(rc, rc);
2228 if (isDataAvailable(0,
"recvBinary", xsink)) {
2230 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
2235 th.finalize(b->
size());
2242 do_read_event(rc, b->
size());
2243 }
while (isDataAvailable(0,
"recvBinary", xsink));
2246 th.finalize(b->
size());
2252 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2260 if (sock == QORE_INVALID_SOCKET) {
2261 se_not_open(
"Socket",
"recvToOutputStream", xsink);
2266 se_in_op(
"Socket",
"recvToOutputStream", xsink);
2269 se_in_op_thread(
"Socket",
"recvToOutputStream", xsink);
2273 qore_socket_op_helper oh(
this);
2277 while (size < 0 || br < size) {
2279 int bn = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - br, DEFAULT_SOCKET_BUFSIZE);
2281 qore_offset_t rc = brecv(xsink,
"recvToOutputStream", buf, bn, 0, timeout);
2290 xsink->
raiseException(
"SOCKET-RECV-ERROR",
"Unexpected end of stream");
2296 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, buf, rc);
2302 os->
write(buf, rc, xsink);
2321 do_data_event(QORE_EVENT_HTTP_HEADERS_READ, source, **hdr);
2322 return hdr.release();
2326 qore_offset_t& rc,
int source,
const char* headers_raw_key =
"headers-raw") {
2335 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"remote closed the connection while reading the HTTP header");
2340 return processHttpHeaderString(xsink, hdr, info, source, headers_raw_key);
2345 QoreHashNode* info,
int source,
const char* headers_raw_key =
"headers-raw") {
2346 const char* buf = hdr->
c_str();
2348 if ((p = (
char*)strstr(buf,
"\r\n"))) {
2351 }
else if ((p = (
char*)strchr(buf,
'\n'))) {
2354 }
else if ((p = (
char*)strchr(buf,
'\r'))) {
2360 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"invalid header received with embedded nulls in "
2361 "Socket::readHTTPHeader()");
2366 if (!(t1 = (
char*)strstr(buf,
"HTTP/"))) {
2367 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"missing HTTP version string in "
2368 "first header line in Socket::readHTTPHeader()");
2375 int flags = CHF_PROCESS;
2382 flags |= CHF_HTTP11;
2388 const char* info_key;
2390 char* t2 = (
char*)strchr(buf + 8,
' ');
2393 if (isdigit(*(t2))) {
2395 if (strlen(t2) > 4) {
2402 info_key =
"response-uri";
2404 char* t2 = (
char*)strchr(buf,
' ');
2409 t1 = strchr(t2,
' ');
2417 info_key =
"request-uri";
2418 flags |= CHF_REQUEST;
2422 if (info || (event_queue && event_data)) {
2424 if (info && event_queue && event_data) {
2427 if (event_queue && event_data) {
2428 do_data_event_intern(QORE_EVENT_SOCKET_DATA_READ, source, **status_line);
2431 info->
setKeyValue(info_key, *status_line,
nullptr);
2433 status_line.release();
2436 bool close = convertHeaderToHash(*h, p, flags, info, &http_exp_chunked_body, headers_raw_key);
2437 do_read_http_header(QORE_EVENT_HTTP_MESSAGE_RECEIVED, *h, source);
2440 if ((flags & CHF_REQUEST) && info) {
2448 DLLLOCAL
int runHeaderCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2450 bool send_aborted =
false,
QoreObject* obj =
nullptr) {
2459 arg->
setKeyValue(
"send_aborted", send_aborted, xsink);
2460 args->push(arg,
nullptr);
2463 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2466 DLLLOCAL
int runTrailerCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2469 if (runCallback(xsink, cname, mname, rv, callback, l,
nullptr))
2472 switch (rv->getType()) {
2480 xsink->
raiseException(
"HTTP-TRAILER-ERROR",
"chunked callback returned type '%s'; expecting 'hash' "
2481 "or 'NOTHING'", rv->getTypeName());
2487 DLLLOCAL
int runDataCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2494 args->push(arg,
nullptr);
2497 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2516 if (sock == QORE_INVALID_SOCKET) {
2517 se_not_open(cname, mname, xsink,
"runCallback");
2518 return QSE_NOT_OPEN;
2524 DLLLOCAL
int sendHttpChunkedWithCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2526 bool* aborted =
nullptr) {
2528 assert(!aborted || !(*aborted));
2530 if (sock == QORE_INVALID_SOCKET) {
2531 se_not_open(cname, mname, xsink,
"sendHttpChunkedWithCallback");
2532 return QSE_NOT_OPEN;
2536 se_in_op(cname, mname, xsink);
2539 se_in_op_thread(cname, mname, xsink);
2543 PrivateQoreSocketThroughputHelper th(
this,
true);
2546 bool nb = (timeout_ms >= 0);
2548 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2552 qore_socket_op_helper oh(
this);
2561 bool data_available = tryReadSocketData(mname, xsink);
2563 if (data_available || *xsink) {
2565 return *xsink ? -1 : 0;
2571 rc = runCallback(xsink, cname, mname, res, send_callback, &l);
2580 const char* data_ptr =
nullptr;
2581 size_t data_size = 0;
2583 switch (res->getType()) {
2591 data_ptr = str->
c_str();
2592 data_size = str->
size();
2604 data_ptr =
static_cast<const char*
>(b->
getPtr());
2605 data_size = b->
size();
2617 const char* key = hi.getKey();
2624 do_header(key, buf, li.getValue());
2626 do_header(key, buf, v);
2637 xsink->
raiseException(
"SOCKET-CALLBACK-ERROR",
"HTTP chunked data callback returned type '%s'; expecting one of: 'string', 'binary', 'hash', 'nothing' (or 'NULL')", res->getTypeName());
2643 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2649 if (data_ptr && data_size) {
2650 rc = sendIntern(xsink, cname, mname, data_ptr, data_size, timeout_ms, total,
true);
2655 if (buf.
empty() && (!data_ptr || !data_size)) {
2656 buf.
set(
"0\r\n\r\n");
2660 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2666 switch (res->getType()) {
2669 if (!str->
empty()) {
2670 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *str);
2678 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *b);
2685 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, source, *h);
2693 if (aborted && *xsink) {
2694 bool data_available = tryReadSocketData(mname, xsink);
2696 if (data_available) {
2698 return *xsink ? -1 : 0;
2707 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2713 return rc < 0 || sock == QORE_INVALID_SOCKET ? -1 : 0;
2716 DLLLOCAL
int sendIntern(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2717 int timeout_ms,
int64& total,
bool stream =
false) {
2723 bool nb = (timeout_ms >= 0);
2728 rc = ssl->write(mname, buf + bs, size - bs, timeout_ms, xsink);
2731 rc = ::send(sock, buf + bs, size - bs, 0);
2738 if (nb && (errno == EAGAIN
2740 || errno == EWOULDBLOCK
2743 if (!isWriteFinished(timeout_ms, mname, xsink)) {
2746 se_timeout(
"Socket", mname, timeout_ms, xsink);
2752 if (errno != EINTR) {
2754 xsink->
raiseErrnoException(
"SOCKET-SEND-ERROR", errno,
"error while executing %s::%s()", cname, mname);
2758 if (!stream && errno == EPIPE)
2762 if (!stream && errno == ECONNRESET)
2773 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2778 do_send_event(rc, bs, size);
2789 DLLLOCAL
int send(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2790 int timeout_ms = -1,
int source = QORE_SOURCE_SOCKET) {
2792 if (sock == QORE_INVALID_SOCKET) {
2793 se_not_open(cname, mname, xsink,
"send");
2794 return QSE_NOT_OPEN;
2798 se_in_op(cname, mname, xsink);
2801 se_in_op_thread(cname, mname, xsink);
2808 PrivateQoreSocketThroughputHelper th(
this,
true);
2811 bool nb = (timeout_ms >= 0);
2813 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2819 qore_offset_t rc = sendIntern(xsink, cname, mname, buf, size, timeout_ms, total);
2822 if (rc > 0 && source > 0) {
2823 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, buf, size);
2826 return rc < 0 || sock == QORE_INVALID_SOCKET ? rc : 0;
2831 if (sock == QORE_INVALID_SOCKET) {
2832 se_not_open(
"Socket",
"sendFromInputStream", xsink);
2837 se_in_op(
"Socket",
"sendFromInputStream", xsink);
2840 se_in_op_thread(
"Socket",
"sendFromInputStream", xsink);
2844 qore_socket_op_helper oh(
this);
2846 PrivateQoreSocketThroughputHelper th(
this,
true);
2849 bool nb = (timeout >= 0);
2851 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2855 char buf[DEFAULT_SOCKET_BUFSIZE];
2858 while (size < 0 || sent < size) {
2859 int64 toRead = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - sent, DEFAULT_SOCKET_BUFSIZE);
2863 r = is->
read(buf, toRead, xsink);
2872 xsink->
raiseException(
"SOCKET-SEND-ERROR",
"Unexpected end of stream");
2878 qore_offset_t rc = sendIntern(xsink,
"Socket",
"sendFromInputStream", buf, r, timeout, total);
2882 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, QORE_SOURCE_SOCKET, buf, r);
2889 if (sock == QORE_INVALID_SOCKET) {
2890 se_not_open(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2895 se_in_op(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2898 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2902 qore_socket_op_helper oh(
this);
2904 PrivateQoreSocketThroughputHelper th(
this,
true);
2907 bool nb = (timeout >= 0);
2909 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2915 buf->preallocate(max_chunk_size);
2921 r = is->
read((
void*)buf->getPtr(),
sizeof(max_chunk_size), xsink);
2928 str.
sprintf(
"%x\r\n", (
int)r);
2929 int rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2933 bool trailers =
false;
2937 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", (
const char*)buf->getPtr(), r, timeout, total,
true);
2940 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, QORE_SOURCE_SOCKET, buf->getPtr(), r);
2941 }
else if (trailer_callback) {
2945 if (runTrailerCallback(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", *trailer_callback, l, h))
2949 do_headers(str, *h, 0,
false);
2951 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2955 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, **h);
2963 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2977 if (sock == QORE_INVALID_SOCKET) {
2978 se_not_open(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2983 se_in_op(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2986 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2996 const char* key = hi.getKey();
3001 do_header(key, buf, li.getValue());
3004 do_header(key, buf, v);
3009 sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyTrailer", buf.
getBuffer(), buf.
size(), timeout, total,
true);
3011 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, *headers);
3015 DLLLOCAL
void getSendHttpMessageHeaders(
QoreString& hdr,
QoreHashNode* info,
const char* method,
const char* path,
3016 const char* http_version,
const QoreHashNode* headers,
size_t size,
int source) {
3018 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3025 getSendHttpMessageHeadersCommon(hdr, info, headers, size, source);
3029 size_t size,
int source) {
3031 do_send_http_message_event(hdr, headers, source);
3036 do_headers(hdr, headers, size);
3040 const char* method,
const char* path,
const char* http_version,
const QoreHashNode* headers,
3048 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3055 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3056 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3068 hdr.
sprintf(
"HTTP/%s %03d %s", http_version, code, desc);
3076 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3077 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3086 assert(!(data && send_callback));
3087 assert(!(data && input_stream));
3088 assert(!(send_callback && input_stream));
3091 do_send_http_message_event(hdr, headers, source);
3096 do_headers(hdr, headers, size && data ? size : 0);
3102 if ((rc = send(xsink, cname, mname, hdr.
c_str(), hdr.
size(), timeout_ms, -1)))
3107 int rc = send(xsink, cname, mname, (
char*)data, size, timeout_ms, -1);
3110 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, *body);
3112 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, data, size);
3116 }
else if (send_callback) {
3118 assert(!aborted || !(*aborted));
3119 return sendHttpChunkedWithCallback(xsink, cname, mname, *send_callback, *l, source, timeout_ms, aborted);
3120 }
else if (input_stream) {
3122 sendHttpChunkedBodyFromInputStream(input_stream, max_chunk_size, timeout_ms, xsink, l, trailer_callback);
3123 return *xsink ? -1 : 0;
3132 if (sock == QORE_INVALID_SOCKET) {
3133 se_not_open(cname,
"readHTTPChunkedBodyBinary", xsink);
3138 se_in_op(cname,
"readHTTPChunkedBodyBinary", xsink);
3141 se_in_op_thread(cname,
"readHTTPChunkedBodyBinary", xsink);
3146 if (http_exp_chunked_body)
3147 http_exp_chunked_body =
false;
3149 qore_socket_op_helper oh(
this);
3162 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 1, 0, timeout,
false);
3166 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3173 if (!state && c ==
'\r')
3175 else if (state && c ==
'\n')
3189 char* p = (
char*)strchr(str.
getBuffer(),
';');
3192 long size = strtol(str.
c_str(), 0, 16);
3193 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
size(), source);
3199 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3206 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3210 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, bs, 0, timeout,
false);
3215 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3220 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, buf, (
size_t)rc);
3224 os->
write(buf, rc, xsink);
3246 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 2 - br, 0, timeout,
false);
3250 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3257 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3259 if (recv_callback && !os) {
3260 if (runDataCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, *b,
true))
3276 if (!recv_callback && !os) {
3284 return recv_callback ? 0 : h.release();
3286 if (recv_callback) {
3289 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3290 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3293 if (recv_callback) {
3294 runHeaderCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, h->
empty() ?
nullptr : *h,
3295 info.release(),
false, obj);
3306 if (sock == QORE_INVALID_SOCKET) {
3307 se_not_open(cname,
"readHTTPChunkedBody", xsink);
3312 se_in_op(cname,
"readHTTPChunkedBody", xsink);
3315 se_in_op_thread(cname,
"readHTTPChunkedBody", xsink);
3320 if (http_exp_chunked_body)
3321 http_exp_chunked_body =
false;
3323 qore_socket_op_helper oh(
this);
3336 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 1, 0, timeout,
false);
3340 se_closed(cname,
"readHTTPChunkedBody", xsink);
3347 if (!state && c ==
'\r')
3349 else if (state && c ==
'\n')
3363 char* p = (
char*)strchr(str.
getBuffer(),
';');
3367 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
strlen(), source);
3373 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3383 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3388 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, bs, 0, timeout,
false);
3392 se_closed(cname,
"readHTTPChunkedBody", xsink);
3398 buf->concat(tbuf, rc);
3400 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, tbuf, (
size_t)rc);
3416 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 2 - br, 0, timeout,
false);
3420 se_closed(cname,
"readHTTPChunkedBody", xsink);
3427 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3429 if (recv_callback) {
3430 if (runDataCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, *buf,
true))
3443 if (!recv_callback) {
3451 return recv_callback ? 0 : h.release();
3453 if (recv_callback) {
3456 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3457 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3460 if (recv_callback) {
3461 runHeaderCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, h->
empty() ?
nullptr : *h,
3462 info.release(),
false, obj);
3469 DLLLOCAL
static void do_accept_encoding(
char* t,
QoreHashNode& info) {
3478 while (*a && *a !=
';' && *a !=
',')
3482 l->push(str.release(),
nullptr);
3492 info.
setKeyValue(
"accept-encoding", l.release(), 0);
3495 DLLLOCAL
bool do_accept_charset(
char* t,
QoreHashNode& info) {
3496 bool acceptcharset =
false;
3511 if (*a ==
'u' || *a ==
'U') {
3513 if (*a ==
't' || *a ==
'T') {
3515 if (*a ==
'f' || *a ==
'F') {
3527 }
else if (*a ==
',') {
3531 }
else if (*a ==
';') {
3540 acceptcharset =
true;
3544 ac->concat(t, div - t);
3549 info.
setKeyValue(
"accept-charset", ac.release(), 0);
3550 acceptcharset =
true;
3554 return acceptcharset;
3559 bool* chunked =
nullptr,
const char* headers_raw_key =
"headers-raw") {
3560 bool close = !(flags & CHF_HTTP11);
3562 const char* senc =
nullptr;
3564 bool acceptcharset =
false;
3572 std::string raw_key;
3577 if ((p = strstr(buf,
"\r\n"))) {
3580 }
else if ((p = strchr(buf,
'\n'))) {
3583 }
else if ((p = strchr(buf,
'\r'))) {
3588 char* t = strchr(buf,
':');
3593 while (t && qore_isblank(*t))
3603 if (flags & CHF_PROCESS) {
3604 if (!strcmp(buf,
"connection")) {
3605 if (flags & CHF_HTTP11) {
3606 if (strcasestr(t,
"close"))
3609 if (strcasestr(t,
"keep-alive"))
3612 }
else if (!strcmp(buf,
"content-type")) {
3613 char* a = strcasestr(t,
"charset=");
3616 char* e = strchr(a + 8,
';');
3620 cs.
concat(a + 8, e - a - 8);
3629 size_t len = cs.
size();
3639 }
while (a > t && (*a ==
' ' || *a ==
';'));
3646 ct->concat(t, a - t + 1);
3652 info->
setKeyValue(
"body-content-type", ct.release(),
nullptr);
3658 info->
setKeyValue(
"body-content-type", val->refSelf(),
nullptr);
3661 }
else if (chunked && !strcmp(buf,
"transfer-encoding") && !strcasecmp(t,
"chunked")) {
3664 if (!strcmp(buf,
"accept-charset"))
3665 acceptcharset = do_accept_charset(t, *info);
3666 else if ((flags & CHF_REQUEST) && !strcmp(buf,
"accept-encoding"))
3667 do_accept_encoding(t, *info);
3672 if (raw_hdr && val) {
3673 val_copy = val->realCopy();
3677 hash_assignment_priv ha(*h, buf);
3678 if (!(*ha).isNothing()) {
3680 if ((*ha).getType() ==
NT_LIST) {
3684 l->
push(ha.swap(l),
nullptr);
3686 l->
push(val.release(),
nullptr);
3688 ha.assign(val.release(), 0);
3692 hash_assignment_priv ha(*raw_hdr, raw_key);
3693 if (!(*ha).isNothing()) {
3695 if ((*ha).getType() ==
NT_LIST) {
3699 l->
push(ha.swap(l),
nullptr);
3701 l->
push(val_copy.release(),
nullptr);
3703 ha.assign(val_copy.release(),
nullptr);
3707 if ((flags & CHF_PROCESS)) {
3711 if (info && !acceptcharset)
3718 DLLLOCAL
int recvix(
const char* meth,
int len,
void* targ,
int timeout_ms,
ExceptionSink* xsink) {
3720 if (sock == QORE_INVALID_SOCKET) {
3721 se_not_open(
"Socket", meth, xsink,
"recvix");
3722 return QSE_NOT_OPEN;
3726 se_in_op(
"Socket", meth, xsink);
3729 se_in_op_thread(
"Socket", meth, xsink);
3733 PrivateQoreSocketThroughputHelper th(
this,
false);
3738 qore_offset_t rc = brecv(xsink, meth, buf, len - br, 0, timeout_ms);
3740 do_read_error(rc, meth, timeout_ms, xsink);
3744 memcpy(targ, buf, rc);
3752 do_data_event(QORE_EVENT_SOCKET_DATA_READ, QORE_SOURCE_SOCKET, targ, br);
3758 if (warn_callback_arg) {
3759 warn_callback_arg.
discard(xsink);
3762 warn_queue->deref(xsink);
3763 warn_queue =
nullptr;
3765 tp_warning_bs = 0.0;
3773 if (warning_ms <= 0 && warning_bs <= 0) {
3774 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);
3784 warn_queue->
deref(xsink);
3785 warn_callback_arg.
discard(xsink);
3788 warn_queue = qholder.release();
3789 warn_callback_arg = holder.release();
3790 tl_warning_us = (
int64)warning_ms * 1000;
3791 tp_warning_bs = warning_bs;
3792 tp_us_min = min_ms * 1000;
3795 DLLLOCAL
void getUsageInfo(
QoreHashNode& h, qore_socket_private& s)
const {
3803 h.
setKeyValue(
"bytes_sent", tp_bytes_sent + s.tp_bytes_sent, 0);
3804 h.
setKeyValue(
"bytes_recv", tp_bytes_recv + s.tp_bytes_sent, 0);
3805 h.
setKeyValue(
"us_sent", tp_us_sent + s.tp_us_sent, 0);
3806 h.
setKeyValue(
"us_recv", tp_us_recv + s.tp_us_recv, 0);
3829 DLLLOCAL
void clearStats() {
3836 DLLLOCAL
void doTimeoutWarning(
const char* op,
int64 dt) {
3838 assert(dt > tl_warning_us);
3846 if (warn_callback_arg)
3849 warn_queue->pushAndTakeRef(h);
3852 DLLLOCAL
void doThroughputWarning(
bool send,
int64 bytes,
int64 dt,
double bs) {
3854 assert(bs < tp_warning_bs);
3864 if (warn_callback_arg)
3867 warn_queue->pushAndTakeRef(h);
3870 DLLLOCAL
bool pendingHttpChunkedBody()
const {
3871 return http_exp_chunked_body && sock != QORE_INVALID_SOCKET;
3874 DLLLOCAL
void setSslVerifyMode(
int mode) {
3876 ssl_verify_mode = mode;
3878 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3881 DLLLOCAL
void acceptAllCertificates(
bool accept_all =
true) {
3882 ssl_accept_all_certs = accept_all;
3884 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3889 ssl_err_str->
concat(
"; ");
3890 ssl_err_str->
concat(err_str);
3893 ssl_err_str = err_str;
3898 sock.priv->getUsageInfo(h, *s.priv);
3901 DLLLOCAL
static qore_socket_private* get(
QoreSocket& sock) {
3905 DLLLOCAL
static const qore_socket_private* get(
const QoreSocket& sock) {
3909 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:550
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:577
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 * copy() const
performs a copy of the hash and returns the new hash
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:127
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:74
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