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
79static constexpr int SOCK_POLLIN = (1 << 0);
80static constexpr int SOCK_POLLOUT = (1 << 1);
81static constexpr int SOCK_POLLERR = (1 << 2);
83DLLLOCAL
void concat_target(
QoreString& str,
const struct sockaddr *addr,
const char* type =
"target");
84DLLLOCAL
int do_read_error(ssize_t rc,
const char* method_name,
int timeout_ms,
ExceptionSink* xsink);
85DLLLOCAL
int sock_get_raw_error();
86DLLLOCAL
int sock_get_error();
87DLLLOCAL
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);
89DLLLOCAL
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);
92DLLLOCAL
void se_in_op(
const char* cname,
const char* meth,
ExceptionSink* xsink);
93DLLLOCAL
void se_in_op_thread(
const char* cname,
const char* meth,
ExceptionSink* xsink);
94DLLLOCAL
void se_not_open(
const char* cname,
const char* meth,
ExceptionSink* xsink,
const char* extra =
nullptr);
95DLLLOCAL
void se_timeout(
const char* cname,
const char* meth,
int timeout_ms,
ExceptionSink* xsink,
96 const char* extra =
nullptr);
97DLLLOCAL
void se_closed(
const char* cname,
const char* mname,
ExceptionSink* xsink);
100#define GETSOCKOPT_ARG_4 char*
101#define SETSOCKOPT_ARG_4 const char*
102#define SHUTDOWN_ARG SD_BOTH
103#define QORE_INVALID_SOCKET ((int)INVALID_SOCKET)
104#define QORE_SOCKET_ERROR SOCKET_ERROR
105DLLLOCAL
int check_windows_rc(
int rc);
106DLLLOCAL
int windows_set_errno();
109#define ECONNRESET WSAECONNRESET
114#define GETSOCKOPT_ARG_4 void*
115#define SETSOCKOPT_ARG_4 void*
116#define SHUTDOWN_ARG SHUT_RDWR
117#define QORE_INVALID_SOCKET -1
118#define QORE_SOCKET_ERROR -1
122class PrivateDataListHolder {
124 DLLLOCAL PrivateDataListHolder(
ExceptionSink* xsink) : xsink(xsink) {
127 DLLLOCAL ~PrivateDataListHolder() {
128 for (
auto& i : pd_vec)
136 pd_vec.push_back(pd);
141 typedef std::vector<T*> pd_vec_t;
146hashdecl qore_socketsource_private {
150 DLLLOCAL qore_socketsource_private() : address(0), hostname(0) {
153 DLLLOCAL ~qore_socketsource_private() {
154 if (address) address->deref();
155 if (hostname) hostname->deref();
163 DLLLOCAL
void setAddress(
const char* addr) {
168 DLLLOCAL
void setHostName(
const char* host) {
175 o->
setValue(
"source", address, xsink);
180 o->
setValue(
"source_host", hostname, xsink);
186class OptionalNonBlockingHelper {
188 qore_socket_private& sock;
192 DLLLOCAL OptionalNonBlockingHelper(qore_socket_private& s,
bool n_set,
ExceptionSink* xs);
193 DLLLOCAL ~OptionalNonBlockingHelper();
196class PrivateQoreSocketTimeoutBase {
198 DLLLOCAL PrivateQoreSocketTimeoutBase(qore_socket_private* s) : sock(s), start(sock ? q_clock_getmicros() : 0) {
202 hashdecl qore_socket_private* sock;
206class PrivateQoreSocketTimeoutHelper :
public PrivateQoreSocketTimeoutBase {
208 DLLLOCAL PrivateQoreSocketTimeoutHelper(qore_socket_private* s,
const char* op);
209 DLLLOCAL ~PrivateQoreSocketTimeoutHelper();
215class PrivateQoreSocketThroughputHelper :
public PrivateQoreSocketTimeoutBase {
217 DLLLOCAL PrivateQoreSocketThroughputHelper(qore_socket_private* s,
bool snd);
218 DLLLOCAL ~PrivateQoreSocketThroughputHelper();
220 DLLLOCAL
void finalize(
int64 bytes);
226hashdecl qore_socket_private;
228hashdecl qore_socket_op_helper {
230 qore_socket_private* s;
233 DLLLOCAL qore_socket_op_helper(qore_socket_private* sock);
234 DLLLOCAL ~qore_socket_op_helper();
237class SSLSocketHelperHelper {
239 qore_socket_private* s;
240 SSLSocketHelper* ssl;
241 bool context_saved =
false;
244 DLLLOCAL SSLSocketHelperHelper(qore_socket_private* sock,
bool set_thread_context =
false);
246 DLLLOCAL ~SSLSocketHelperHelper();
248 DLLLOCAL
void error();
251constexpr int SCIPS_CONNECT = 0;
252constexpr int SCIPS_CHECK_CONNECT = 1;
254class SocketConnectInetPollState :
public AbstractPollState {
256 DLLLOCAL SocketConnectInetPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* host,
257 const char* service,
int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0);
269 qore_socket_private* sock;
270 std::string host, service;
271 hashdecl addrinfo* p =
nullptr;
273 int state = SCIPS_CONNECT;
288class SocketConnectUnixPollState :
public AbstractPollState {
290 DLLLOCAL SocketConnectUnixPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* name,
291 int type = SOCK_STREAM,
int protocol = 0);
302 qore_socket_private* sock;
304 hashdecl sockaddr_un addr;
305 int state = SCIPS_CONNECT;
314class SocketConnectSslPollState :
public AbstractPollState {
316 DLLLOCAL SocketConnectSslPollState(
ExceptionSink* xsink, qore_socket_private* sock,
328 qore_socket_private* sock;
335class SocketAcceptPollState :
public AbstractPollState {
337 DLLLOCAL SocketAcceptPollState(
ExceptionSink* xsink, qore_socket_private* sock);
339 qore_socket_private* sock;
342class SocketAcceptSslPollState :
public AbstractPollState {
343 DLLLOCAL SocketAcceptSslPollState(
ExceptionSink* xsink, qore_socket_private* sock,
346 SSLSocketHelperHelper sshh(sock,
true);
348 sock->do_start_ssl_event();
350 if (rc = sock->ssl->setServer(xsink,
"acceptSSL", sock->sock, cert, pkey)) {
356 ssl->startAccept(xsink);
361class SocketSendPollState :
public AbstractPollState {
363 DLLLOCAL SocketSendPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* data,
size_t size);
374 qore_socket_private* sock;
380class SocketRecvPollState :
public AbstractPollState {
382 DLLLOCAL SocketRecvPollState(
ExceptionSink* xsink, qore_socket_private* sock,
size_t size);
393 DLLLOCAL
virtual QoreValue takeOutput() {
400 qore_socket_private* sock;
406class SocketRecvUntilBytesPollState :
public AbstractPollState {
408 DLLLOCAL SocketRecvUntilBytesPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* bytes,
420 DLLLOCAL
virtual QoreValue takeOutput() {
421 size_t len = bin->size();
428 qore_socket_private* sock;
439hashdecl qore_socket_private {
440 friend class PrivateQoreSocketTimeoutHelper;
441 friend class PrivateQoreSocketThroughputHelper;
442 friend class SocketConnectInetPollState;
445 static thread_local qore_socket_private* current_socket;
447 int sock, sfamily, port, stype, sprot;
450 int64 connection_id = 0;
454 std::string socketname;
456 std::string client_target;
457 SSLSocketHelper* ssl =
nullptr;
458 Queue* event_queue =
nullptr,
459 * warn_queue =
nullptr;
462 std::string assume_http_encoding =
"ISO-8859-1";
465 char rbuf[DEFAULT_SOCKET_BUFSIZE];
471 int64 tl_warning_us = 0;
472 double tp_warning_bs = 0;
473 int64 tp_bytes_sent = 0,
485 http_exp_chunked_body =
false,
486 ssl_accept_all_certs =
false,
487 ssl_capture_remote_cert =
false,
490 ssl_verify_mode = SSL_VERIFY_NONE;
498 DLLLOCAL qore_socket_private(
int n_sock = QORE_INVALID_SOCKET,
int n_sfamily = AF_UNSPEC,
500 sock(n_sock), sfamily(n_sfamily), port(-1), stype(n_stype), sprot(n_prot), enc(n_enc) {
503 DLLLOCAL ~qore_socket_private() {
507 assert(!event_queue);
511 DLLLOCAL
bool isOpen() {
512 return sock != QORE_INVALID_SOCKET;
515 DLLLOCAL
int close() {
516 int rc = close_internal();
519 if (http_exp_chunked_body)
520 http_exp_chunked_body =
false;
528 DLLLOCAL
int close_and_reset() {
529 assert(sock != QORE_INVALID_SOCKET);
533 rc = ::closesocket(sock);
538 if (!rc || sock_get_error() != EINTR)
542 sock = QORE_INVALID_SOCKET;
552 client_target.clear();
556 DLLLOCAL
int close_internal() {
559 ssl_err_str->deref();
560 ssl_err_str =
nullptr;
563 remote_cert->
deref(
nullptr);
564 remote_cert =
nullptr;
574 if (!socketname.empty()) {
576 unlink(socketname.c_str());
584 return close_and_reset();
590 DLLLOCAL
void setAssumedEncoding(
const char* str) {
591 assume_http_encoding = str;
594 DLLLOCAL
const char* getAssumedEncoding()
const {
595 return assume_http_encoding.c_str();
598 DLLLOCAL
int getSendTimeout()
const {
601#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
604 int size =
sizeof(
hashdecl timeval);
606 socklen_t size =
sizeof(
hashdecl timeval);
609 if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
612 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
615 DLLLOCAL
int getRecvTimeout()
const {
618#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
621 int size =
sizeof(
hashdecl timeval);
623 socklen_t size =
sizeof(
hashdecl timeval);
626 if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
629 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
632 DLLLOCAL
int getPort() {
634 if (sock == QORE_INVALID_SOCKET || (sfamily != AF_INET && sfamily != AF_INET6) || port > 0)
638 hashdecl sockaddr_storage addr;
639#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
641 int size =
sizeof addr;
643 socklen_t size =
sizeof addr;
646 if (getsockname(sock, (
struct sockaddr *)&addr, (socklen_t *)&size) < 0)
649 port = q_get_port_from_addr((
const struct sockaddr *)&addr);
663 size_t offset = hdr.
size();
668 q_fix_decimal(&hdr, offset);
685 DLLLOCAL
static void do_headers(
QoreString& hdr,
const QoreHashNode* headers,
size_t size,
bool addsize =
true) {
693 const char* key = hi.getKey();
694 if (addsize && !strcasecmp(key,
"transfer-encoding"))
696 if ((addsize || size) && !strcasecmp(key,
"content-length")) {
703 do_header(key, hdr, li.getValue());
705 do_header(key, hdr, v);
709 if (size || addsize) {
710 hdr.
sprintf(
"Content-Length: %zu\r\n", size);
717 DLLLOCAL
int listen(
int backlog = 20) {
718 if (sock == QORE_INVALID_SOCKET)
723 if (::listen(sock, backlog)) {
730 return ::listen(sock, backlog);
734 DLLLOCAL
int accept_intern(
ExceptionSink* xsink,
struct sockaddr *addr, socklen_t *size,
int timeout_ms = -1) {
738 if (timeout_ms >= 0 && !isDataAvailable(timeout_ms,
"accept", xsink)) {
745 int rc = ::accept(sock, addr, size);
746 if (rc != QORE_INVALID_SOCKET)
750 if (sock_get_error() == EINTR)
753 qore_socket_error(xsink,
"SOCKET-ACCEPT-ERROR",
"error in accept()", 0, 0, 0, addr);
761 if (sock == QORE_INVALID_SOCKET) {
762 xsink->
raiseException(
"SOCKET-NOT-OPEN",
"socket must be opened, bound, and in a listening state before "
763 "new connections can be accepted");
768 se_in_op(
"Socket",
"accept", xsink);
771 se_in_op_thread(
"Socket",
"accept", xsink);
772 return QSE_IN_OP_THREAD;
776 if (sfamily == AF_UNIX) {
778 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"UNIX sockets are not available under Windows");
781 hashdecl sockaddr_un addr_un;
783#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
786 int size =
sizeof(
hashdecl sockaddr_un);
788 socklen_t size =
sizeof(
hashdecl sockaddr_un);
790 rc = accept_intern(xsink, (
struct sockaddr *)&addr_un, (socklen_t *)&size, timeout_ms);
793 if (rc >= 0 && source) {
795 addr->
sprintf(
"UNIX socket: %s", socketname.c_str());
796 source->priv->setAddress(addr);
797 source->priv->setHostName(
"localhost");
800 }
else if (sfamily == AF_INET || sfamily == AF_INET6) {
801 hashdecl sockaddr_storage addr_in;
802#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
805 int size =
sizeof(addr_in);
807 socklen_t size =
sizeof(addr_in);
810 rc = accept_intern(xsink, (
struct sockaddr *)&addr_in, (socklen_t *)&size, timeout_ms);
813 if (rc >= 0 && source) {
814 char host[NI_MAXHOST + 1];
815 char service[NI_MAXSERV + 1];
817 if (!getnameinfo((
struct sockaddr *)&addr_in, qore_get_in_len((
struct sockaddr *)&addr_in), host,
818 sizeof(host), service,
sizeof(service), NI_NUMERICSERV)) {
819 source->priv->setHostName(host);
823 char ifname[INET6_ADDRSTRLEN];
824 if (inet_ntop(addr_in.ss_family, qore_get_in_addr((
struct sockaddr *)&addr_in), ifname,
827 source->priv->setAddress(ifname);
832 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"do not know how to accept connections with address "
833 "family %d", sfamily);
839 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_SOCKET)
const {
858 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
861 event_queue->deref(xsink);
862 event_queue =
nullptr;
865 warn_queue->deref(xsink);
866 warn_queue =
nullptr;
867 if (warn_callback_arg) {
868 warn_callback_arg.
discard(xsink);
869 warn_callback_arg.
clear();
879 event_queue->deref(xsink);
883 event_data = with_data;
886 DLLLOCAL
void do_start_ssl_event() {
888 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_START_SSL));
892 DLLLOCAL
void do_ssl_established_event() {
897 event_queue->pushAndTakeRef(h);
901 DLLLOCAL
void do_connect_event(
int af,
const struct sockaddr* addr,
const char* target,
902 const char* service =
nullptr,
int prt = -1) {
911 q_af_to_hash(af, *h,
nullptr);
917 event_queue->pushAndTakeRef(h);
921 DLLLOCAL
void do_connected_event() {
923 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CONNECTED));
927 DLLLOCAL
void do_data_event_intern(
int event,
int source,
const QoreStringNode& str)
const {
928 assert(event_queue && event_data && str.
size());
931 event_queue->pushAndTakeRef(h.release());
934 DLLLOCAL
void do_data_event(
int event,
int source,
const QoreStringNode& str)
const {
935 if (event_queue && event_data && str.
size()) {
936 do_data_event_intern(event, source, str);
940 DLLLOCAL
void do_data_event(
int event,
int source,
const BinaryNode& b)
const {
941 if (event_queue && event_data && b.
size()) {
944 event_queue->pushAndTakeRef(h.release());
948 DLLLOCAL
void do_data_event(
int event,
int source,
const void* data,
size_t size)
const {
949 if (event_queue && event_data && size) {
954 event_queue->pushAndTakeRef(h.release());
958 DLLLOCAL
void do_header_event(
int event,
int source,
const QoreHashNode& hdr)
const {
959 if (event_queue && event_data && !hdr.
empty()) {
962 event_queue->pushAndTakeRef(h.release());
966 DLLLOCAL
void do_chunked_read(
int event,
size_t bytes,
size_t total_read,
int source) {
969 if (event == QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED)
974 event_queue->pushAndTakeRef(h);
978 DLLLOCAL
void do_read_http_header(
int event,
const QoreHashNode* headers,
int source) {
982 event_queue->pushAndTakeRef(h);
986 DLLLOCAL
void do_send_http_message_event(
const QoreString& str,
const QoreHashNode* headers,
int source) {
988 QoreHashNode* h = getEvent(QORE_EVENT_HTTP_SEND_MESSAGE, source);
992 event_queue->pushAndTakeRef(h);
996 DLLLOCAL
void do_close_event() {
998 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
1002 DLLLOCAL
void do_read_event(
size_t bytes_read,
size_t total_read,
size_t bufsize = 0,
int source = QORE_SOURCE_SOCKET) {
1005 QoreHashNode* h = getEvent(QORE_EVENT_PACKET_READ, source);
1007 h->
setKeyValue(
"total_read", total_read,
nullptr);
1010 h->
setKeyValue(
"total_to_read", bufsize,
nullptr);
1011 event_queue->pushAndTakeRef(h);
1015 DLLLOCAL
void do_send_event(
int bytes_sent,
int total_sent,
int bufsize) {
1020 h->
setKeyValue(
"total_sent", total_sent,
nullptr);
1021 h->
setKeyValue(
"total_to_send", bufsize,
nullptr);
1022 event_queue->pushAndTakeRef(h);
1026 DLLLOCAL
void do_resolve_event(
const char* host,
const char* service = 0) {
1029 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_LOOKUP);
1034 event_queue->pushAndTakeRef(h);
1038 DLLLOCAL
void do_resolved_event(
const struct sockaddr* addr) {
1041 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_RESOLVED);
1047 int prt = q_get_port_from_addr(addr);
1050 q_af_to_hash(addr->sa_family, *h,
nullptr);
1051 event_queue->pushAndTakeRef(h);
1055 DLLLOCAL
int64 getObjectIDForEvents()
const {
1059 DLLLOCAL
int connectUNIX(
const char* p,
int sock_type,
int protocol,
ExceptionSink* xsink) {
1062 QORE_TRACE(
"connectUNIX()");
1065 xsink->
raiseException(
"SOCKET-CONNECTUNIX-ERROR",
"UNIX sockets are not available under Windows");
1071 printd(5,
"qore_socket_private::connectUNIX(%s)\n", p);
1073 hashdecl sockaddr_un addr;
1075 addr.sun_family = AF_UNIX;
1077 strncpy(addr.sun_path, p,
sizeof(addr.sun_path) - 1);
1078 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1079 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_SOCKET_ERROR) {
1080 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"error connecting to UNIX socket: '%s'", p);
1084 do_connect_event(AF_UNIX, (sockaddr*)&addr, p);
1086 if (!::connect(sock, (
const sockaddr *)&addr,
sizeof(
struct sockaddr_un)))
1090 if (sock_get_error() == EINTR)
1096 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, p);
1102 socketname = addr.sun_path;
1105 do_connected_event();
1117 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
const char* cname,
const char* mname,
1120 assert(read || write);
1121 if (sock == QORE_INVALID_SOCKET) {
1122 se_not_open(cname, mname, xsink,
"asyncIoWait");
1126 return asyncIoWait(timeout_ms, read, write, xsink);
1129 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
ExceptionSink* xsink)
const {
1131#if defined HAVE_POLL
1132 return poll_intern(xsink, timeout_ms, read, write);
1133#elif defined HAVE_SELECT
1134 return select_intern(xsink, timeout_ms, read, write);
1136#error no async socket operations supported
1140#if defined HAVE_POLL
1141 DLLLOCAL
int poll_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1148 pollfd fds = {sock, arg, 0};
1150 rc = ::poll(&fds, 1, timeout_ms);
1151 if (rc == -1 && errno == EINTR)
1156 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"poll(2) returned an error");
1157 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
1162#elif defined HAVE_SELECT
1163 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1164 bool aborted =
false;
1165 int rc = select_intern(xsink, timeout_ms, read, write, aborted);
1166 if (rc != QORE_SOCKET_ERROR && aborted)
1171 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write,
bool& aborted)
const {
1178 if (sock >= FD_SETSIZE) {
1179 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);
1183 hashdecl timeval tv;
1194 tv.tv_sec = timeout_ms / 1000;
1195 tv.tv_usec = (timeout_ms % 1000) * 1000;
1197 fd_set* readfd = read ? &sfs : 0;
1198 fd_set* writefd = write ? &sfs : 0;
1200 rc = select(sock + 1, readfd, writefd, &err, &tv);
1202 if (rc != QORE_SOCKET_ERROR) {
1203 if (FD_ISSET(sock, &err))
1207 if (sock_get_error() != EINTR)
1210 if (rc == QORE_SOCKET_ERROR) {
1213 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"select(2) returned an error");
1220 DLLLOCAL
bool tryReadSocketData(
const char* mname,
ExceptionSink* xsink) {
1225 return asyncIoWait(0,
true,
false,
"Socket", mname, xsink);
1229 int rc = ssl->doSSLRW(xsink, mname, rbuf, 1, 0, PEEK,
false);
1230 if (*xsink || (rc == QSE_TIMEOUT)) {
1233 return rc > 0 ? true :
false;
1236 DLLLOCAL
bool isSocketDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1237 return asyncIoWait(timeout_ms,
true,
false,
"Socket", mname, xsink);
1240 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1243 return isSocketDataAvailable(timeout_ms, mname, xsink);
1246 DLLLOCAL
bool isWriteFinished(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1247 return asyncIoWait(timeout_ms,
false,
true,
"Socket", mname, xsink);
1250 DLLLOCAL
int close_and_exit() {
1251 if (sock != QORE_INVALID_SOCKET)
1256 DLLLOCAL
int connectINETTimeout(
int timeout_ms,
const struct sockaddr* ai_addr,
size_t ai_addrlen,
1259 PrivateQoreSocketTimeoutHelper toh(
this,
"connect");
1262 if (!::connect(sock, ai_addr, ai_addrlen))
1266 if (sock_get_error() != EAGAIN) {
1267 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1275 if (errno != EINPROGRESS)
1284 bool aborted =
false;
1285 int rc = select_intern(xsink, timeout_ms,
false,
true, aborted);
1292 if (rc != QORE_SOCKET_ERROR && aborted) {
1293 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1297 int rc = asyncIoWait(timeout_ms,
false,
true,
"Socket",
"connectINETTimeout", xsink);
1303 if (rc == QORE_SOCKET_ERROR && sock_get_error() != EINTR) {
1305 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in asyncIoWait() with "
1306 "Socket::connect() with timeout", 0, 0, 0, ai_addr);
1308 }
else if (rc > 0) {
1309 return checkConnected(xsink,
nullptr, ai_addr, only_timeout);
1313 concat_target(*(*desc), ai_addr);
1323 DLLLOCAL
int checkConnected(
ExceptionSink* xsink,
const char* hostsvc,
const struct sockaddr* ai_addr =
nullptr,
1324 bool only_timeout =
false) {
1328 socklen_t lon =
sizeof(int);
1331 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (GETSOCKOPT_ARG_4)(&val), &lon) == QORE_SOCKET_ERROR) {
1332 if (!only_timeout) {
1333 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
nullptr,
1344 qore_socket_error_intern(val, xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
1353 DLLLOCAL
void confirmConnected(
const char* host) {
1354 do_connected_event();
1358 client_target = host;
1362 DLLLOCAL
int sock_errno_err(
const char* err,
const char* desc,
ExceptionSink* xsink) {
1364 qore_socket_error(xsink, err, desc);
1368 DLLLOCAL
int set_non_blocking(
bool non_blocking,
ExceptionSink* xsink) {
1371 if (sock == QORE_INVALID_SOCKET) {
1377 u_long mode = non_blocking ? 1 : 0;
1378 int rc = ioctlsocket(sock, FIONBIO, &mode);
1379 if (check_windows_rc(rc)) {
1380 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in ioctlsocket(FIONBIO)", xsink);
1386 if ((arg = fcntl(sock, F_GETFL, 0)) < 0) {
1387 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() getting socket descriptor status "
1397 if (fcntl(sock, F_SETFL, arg) < 0) {
1398 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() setting socket descriptor status "
1407 DLLLOCAL
int connectINET(
const char* host,
const char* service,
int timeout_ms,
ExceptionSink* xsink,
1408 int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0) {
1410 family = q_get_af(family);
1411 type = q_get_sock_type(type);
1413 QORE_TRACE(
"qore_socket_private::connectINET()");
1418 printd(5,
"qore_socket_private::connectINET(%s:%s, %dms)\n", host, service, timeout_ms);
1420 do_resolve_event(host, service);
1423 if (ai.
getInfo(xsink, host, service, family, 0, type, protocol))
1430 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1431 do_resolved_event(p->ai_addr);
1433 int prt = q_get_port_from_addr(aip->ai_addr);
1435 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1436 if (!connectINETIntern(host, service, p->ai_family, p->ai_addr, p->ai_addrlen, p->ai_socktype,
1437 p->ai_protocol, prt, timeout_ms, xsink,
true)) {
1446 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1451 DLLLOCAL
int connectINETIntern(
const char* host,
const char* service,
int ai_family,
struct sockaddr* ai_addr,
1452 size_t ai_addrlen,
int ai_socktype,
int ai_protocol,
int prt,
int timeout_ms,
ExceptionSink* xsink,
1453 bool only_timeout =
false) {
1455 printd(5,
"qore_socket_private::connectINETIntern() host: %s service: %s family: %d timeout_ms: %d\n", host,
1456 service, ai_family, timeout_ms);
1457 if ((sock = socket(ai_family, ai_socktype, ai_protocol)) == QORE_INVALID_SOCKET) {
1458 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"cannot establish a connection to %s:%s", host,
1469 if (timeout_ms >= 0) {
1471 if (set_non_blocking(
true, xsink))
1472 return close_and_exit();
1474 do_connect_event(ai_family, ai_addr, host, service, prt);
1476 rc = connectINETTimeout(timeout_ms, ai_addr, ai_addrlen, xsink, only_timeout);
1480 if (set_non_blocking(
false, xsink))
1481 return close_and_exit();
1483 do_connect_event(ai_family, ai_addr, host, service, prt);
1486 rc = ::connect(sock, ai_addr, ai_addrlen);
1489 if (!rc || sock_get_error() != EINTR)
1495 if (!only_timeout || errno == ETIMEDOUT)
1496 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1498 return close_and_exit();
1501 sfamily = ai_family;
1502 stype = ai_socktype;
1503 sprot = ai_protocol;
1508 confirmConnected(host);
1512 DLLLOCAL
int upgradeClientToSSLIntern(
ExceptionSink* xsink,
const char* mname,
const char* sni_target_host,
1515 SSLSocketHelperHelper sshh(
this,
true);
1518 do_start_ssl_event();
1520 if (!sni_target_host && !client_target.empty()) {
1521 sni_target_host = client_target.c_str();
1523 if ((rc = ssl->setClient(xsink, mname, sni_target_host, sock, cert, pkey))
1524 || ssl->connect(mname, timeout_ms,
1527 return rc ? rc : -1;
1529 do_ssl_established_event();
1534 DLLLOCAL
int upgradeServerToSSLIntern(
ExceptionSink* xsink,
const char* mname,
int timeout_ms,
1538 SSLSocketHelperHelper sshh(
this,
true);
1540 do_start_ssl_event();
1541 if (ssl->setServer(xsink, mname, sock, cert, pkey) || ssl->accept(mname, timeout_ms, xsink)) {
1545 do_ssl_established_event();
1551 DLLLOCAL
int openUNIX(
int sock_type = SOCK_STREAM,
int protocol = 0) {
1552 if (sock != QORE_INVALID_SOCKET)
1555 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_INVALID_SOCKET) {
1567 DLLLOCAL
int openINET(
int family = AF_INET,
int sock_type = SOCK_STREAM,
int protocol = 0) {
1568 if (sock != QORE_INVALID_SOCKET)
1571 if ((sock = socket(family, sock_type, protocol)) == QORE_INVALID_SOCKET)
1581 DLLLOCAL
int reuse(
int opt) {
1583 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_ARG_4)&opt,
sizeof(
int));
1587 DLLLOCAL
int bindIntern(
struct sockaddr* ai_addr,
size_t ai_addrlen,
int prt,
bool reuseaddr,
ExceptionSink* xsink = 0) {
1590 if ((::bind(sock, ai_addr, ai_addrlen)) == QORE_SOCKET_ERROR) {
1592 qore_socket_error(xsink,
"SOCKET-BIND-ERROR",
"error in bind()", 0, 0, 0, ai_addr);
1602#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1604 int len = ai_addrlen;
1606 socklen_t len = ai_addrlen;
1609 if (getsockname(sock, ai_addr, &len))
1612 port = q_get_port_from_addr(ai_addr);
1618 DLLLOCAL
int bindUNIX(
ExceptionSink* xsink,
const char* name,
int socktype = SOCK_STREAM,
int protocol = 0) {
1621 xsink->
raiseException(
"SOCKET-BINDUNIX-ERROR",
"UNIX sockets are not available under Windows");
1627 if (openUNIX(socktype, protocol)) {
1628 xsink->
raiseErrnoException(
"SOCKET-BIND-ERROR", errno,
"error opening UNIX socket ('%s') for bind", name);
1632 hashdecl sockaddr_un addr;
1633 addr.sun_family = AF_UNIX;
1635 strncpy(addr.sun_path, name,
sizeof(addr.sun_path) - 1);
1636 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1638 if (bindIntern((sockaddr*)&addr,
sizeof(
struct sockaddr_un), -1,
false, xsink))
1642 socketname = addr.sun_path;
1649 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) {
1651 family = q_get_af(family);
1652 socktype = q_get_sock_type(socktype);
1657 do_resolve_event(name, service);
1658 if (ai.
getInfo(xsink, name, service, family, AI_PASSIVE, socktype, protocol))
1664 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1665 do_resolved_event(p->ai_addr);
1668 if (openINET(aip->ai_family, aip->ai_socktype, protocol)) {
1669 qore_socket_error(xsink,
"SOCKET-BINDINET-ERROR",
"error opening socket for bind", 0, name, service);
1673 int prt = q_get_port_from_addr(aip->ai_addr);
1677 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1678 if (!bindIntern(p->ai_addr, p->ai_addrlen, prt, reuseaddr)) {
1683 en = sock_get_raw_error();
1688 qore_socket_error_intern(en, xsink,
"SOCKET-BIND-ERROR",
"error binding on socket", 0, name, service);
1695 if (sock == QORE_INVALID_SOCKET) {
1696 se_not_open(
"Socket",
"getPeerInfo", xsink);
1700 hashdecl sockaddr_storage addr;
1701 socklen_t len =
sizeof addr;
1702 if (getpeername(sock, (
struct sockaddr*)&addr, &len)) {
1703 qore_socket_error(xsink,
"SOCKET-GETPEERINFO-ERROR",
"error in getpeername()");
1707 return getAddrInfo(addr, len, host_lookup);
1713 if (sock == QORE_INVALID_SOCKET) {
1714 se_not_open(
"Socket",
"getSocketInfo", xsink);
1718 hashdecl sockaddr_storage addr;
1719#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1721 int len =
sizeof addr;
1723 socklen_t len =
sizeof addr;
1726 if (getsockname(sock, (
struct sockaddr*)&addr, &len)) {
1727 qore_socket_error(xsink,
"SOCKET-GETSOCKETINFO-ERROR",
"error in getsockname()");
1731 return getAddrInfo(addr, len, host_lookup);
1734 DLLLOCAL
QoreHashNode* getAddrInfo(
const struct sockaddr_storage& addr, socklen_t len,
bool host_lookup =
true)
const {
1737 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1739 char host[NI_MAXHOST + 1];
1741 if (!getnameinfo((
struct sockaddr*)&addr, qore_get_in_len((
struct sockaddr*)&addr), host,
sizeof(host), 0, 0, 0)) {
1749 char ifname[INET6_ADDRSTRLEN];
1750 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr*)&addr), ifname,
sizeof(ifname))) {
1757 if (addr.ss_family == AF_INET) {
1758 hashdecl sockaddr_in* s = (
hashdecl sockaddr_in*)&addr;
1759 tport = ntohs(s->sin_port);
1761 hashdecl sockaddr_in6* s = (
hashdecl sockaddr_in6*)&addr;
1762 tport = ntohs(s->sin6_port);
1768 else if (addr.ss_family == AF_UNIX) {
1769 assert(!socketname.empty());
1785 hashdecl sockaddr_storage addr;
1787 socklen_t len =
sizeof addr;
1788 if (getpeername(sock, (
struct sockaddr*)&addr, &len))
1791 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1793 char ifname[INET6_ADDRSTRLEN];
1794 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr *)&addr), ifname,
sizeof(ifname))) {
1799 char host[NI_MAXHOST + 1];
1800 if (!getnameinfo((
struct sockaddr *)&addr, qore_get_in_len((
struct sockaddr *)&addr), host,
sizeof(host),
1806 else if (addr.ss_family == AF_UNIX) {
1808 hashdecl sockaddr_un *addr_un = (
hashdecl sockaddr_un *)&addr;
1809 astr->
sprintf(
"UNIX socket: %s", addr_un->sun_path);
1822 DLLLOCAL
int readByteFromBuffer(
char& output) {
1824 assert(sock != QORE_INVALID_SOCKET);
1831 output = *(rbuf + bufoffset);
1843 DLLLOCAL ssize_t brecv(
ExceptionSink* xsink,
const char* meth,
char*& buf,
size_t bs,
int flags,
1844 int timeout,
bool do_event =
true) {
1847 assert(sock != QORE_INVALID_SOCKET);
1852 buf = rbuf + bufoffset;
1871 if (timeout != -1 && !isDataAvailable(timeout, meth, xsink)) {
1875 se_timeout(
"Socket", meth, timeout, xsink);
1883 rc = ::recv(sock, rbuf, DEFAULT_SOCKET_BUFSIZE, flags);
1884 if (rc == QORE_SOCKET_ERROR) {
1889 if (errno == ECONNRESET) {
1890 se_closed(
"Socket", meth, xsink);
1894 qore_socket_error(xsink,
"SOCKET-RECV-ERROR",
"error in recv()", meth);
1904 rc = ssl->read(meth, rbuf, DEFAULT_SOCKET_BUFSIZE, timeout, xsink);
1912 if (rc > (ssize_t)bs) {
1920 do_read_event(rc, rc);
1934 bool exit_early =
false) {
1937 if (sock == QORE_INVALID_SOCKET) {
1938 se_not_open(
"Socket", meth, xsink,
"readHTTPData");
1943 PrivateQoreSocketThroughputHelper th(
this,
false);
1958 rc = brecv(xsink, meth, buf, 1, 0, timeout,
false);
1969 se_closed(
"Socket", meth, xsink);
1971 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"socket closed on remote end "
1972 "while reading header data after reading " QSD
" byte%s", count, count == 1 ?
"" :
"s");
1978 if (++count == QORE_MAX_HEADER_SIZE) {
1979 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"header size cannot exceed " QSD
" bytes", count);
1990 if (exit_early && hdr->
empty())
1997 }
else if (c ==
'\r') {
2012 case 0: hdr->concat(
'\r');
break;
2013 case 1: hdr->concat(
"\r\n");
break;
2014 case 2: hdr->concat(
"\r\n\r");
break;
2015 case 3: hdr->concat(
'\n');
break;
2024 th.finalize(hdr->
size());
2025 return hdr.release();
2029 int source = QORE_SOURCE_SOCKET) {
2031 if (sock == QORE_INVALID_SOCKET) {
2032 se_not_open(
"Socket",
"recv", xsink,
"recv");
2038 se_in_op(
"Socket",
"recv", xsink);
2041 se_in_op_thread(
"Socket",
"recv", xsink);
2045 PrivateQoreSocketThroughputHelper th(
this,
false);
2047 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2054 rc = brecv(xsink,
"recv", buf, bs, 0, timeout,
false);
2060 printd(5,
"qore_socket_private::recv(" QSD
", %d) bs=" QSD
", br=" QSD
", rc=" QSD
", errno: %d "
2061 "(%s)\n", bufsize, timeout, bs, str->
size(), rc, errno, strerror(errno));
2069 do_read_event(rc, str->
size(), bufsize, source);
2073 if (str->
size() >= (
size_t)bufsize)
2075 if ((bufsize - str->
size()) < bs)
2076 bs = bufsize - str->
size();
2080 printd(5,
"qore_socket_private::recv() received " QSD
" byte(s), bufsize=" QSD
", strlen=" QSD
" str='%s'\n",
2087 th.finalize(str->
size());
2094 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2096 return str.release();
2100 int source = QORE_SOURCE_SOCKET) {
2102 if (sock == QORE_INVALID_SOCKET) {
2103 se_not_open(
"Socket",
"recv", xsink,
"recvAll");
2109 se_in_op(
"Socket",
"recv", xsink);
2112 se_in_op_thread(
"Socket",
"recv", xsink);
2116 PrivateQoreSocketThroughputHelper th(
this,
false);
2122 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2129 do_read_event(rc, rc);
2132 if (isDataAvailable(0,
"recv", xsink)) {
2134 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
2140 th.finalize(str->
size());
2146 do_read_event(rc, str->
size());
2147 }
while (isDataAvailable(0,
"recv", xsink));
2150 th.finalize(str->
size());
2158 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2160 return str.release();
2163 DLLLOCAL
int recv(
int fd, ssize_t size,
int timeout_ms,
ExceptionSink* xsink);
2166 int source = QORE_SOURCE_SOCKET) {
2168 if (sock == QORE_INVALID_SOCKET) {
2169 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinary");
2175 se_in_op(
"Socket",
"recvBinary", xsink);
2178 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2182 PrivateQoreSocketThroughputHelper th(
this,
false);
2184 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2190 rc = brecv(xsink,
"recvBinary", buf, bs, 0, timeout);
2197 if (b->
size() >= (
size_t)bufsize)
2199 if ((bufsize - b->
size()) < bs)
2200 bs = bufsize - b->
size();
2204 th.finalize(b->
size());
2214 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2216 printd(5,
"qore_socket_private::recvBinary() received " QSD
" byte(s), bufsize=" QSD
", blen=" QSD
"\n", b->
size(), bufsize, b->
size());
2220 DLLLOCAL
BinaryNode* recvBinaryAll(
ExceptionSink* xsink,
int timeout, ssize_t& rc,
int source = QORE_SOURCE_SOCKET) {
2222 if (sock == QORE_INVALID_SOCKET) {
2223 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinaryAll");
2229 se_in_op(
"Socket",
"recvBinary", xsink);
2232 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2236 PrivateQoreSocketThroughputHelper th(
this,
false);
2243 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2250 do_read_event(rc, rc);
2253 if (isDataAvailable(0,
"recvBinary", xsink)) {
2255 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
2260 th.finalize(b->
size());
2267 do_read_event(rc, b->
size());
2268 }
while (isDataAvailable(0,
"recvBinary", xsink));
2271 th.finalize(b->
size());
2277 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2285 if (sock == QORE_INVALID_SOCKET) {
2286 se_not_open(
"Socket",
"recvToOutputStream", xsink);
2291 se_in_op(
"Socket",
"recvToOutputStream", xsink);
2294 se_in_op_thread(
"Socket",
"recvToOutputStream", xsink);
2298 qore_socket_op_helper oh(
this);
2302 while (size < 0 || br < size) {
2304 int bn = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - br, DEFAULT_SOCKET_BUFSIZE);
2306 ssize_t rc = brecv(xsink,
"recvToOutputStream", buf, bn, 0, timeout);
2315 xsink->
raiseException(
"SOCKET-RECV-ERROR",
"Unexpected end of stream");
2321 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, buf, rc);
2327 os->
write(buf, rc, xsink);
2346 do_data_event(QORE_EVENT_HTTP_HEADERS_READ, source, **hdr);
2347 return hdr.release();
2351 ssize_t& rc,
int source,
const char* headers_raw_key =
"headers-raw") {
2360 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"remote closed the connection while reading the HTTP header");
2365 return processHttpHeaderString(xsink, hdr, info, source, headers_raw_key);
2370 QoreHashNode* info,
int source,
const char* headers_raw_key =
"headers-raw") {
2371 const char* buf = hdr->
c_str();
2373 if ((p = (
char*)strstr(buf,
"\r\n"))) {
2376 }
else if ((p = (
char*)strchr(buf,
'\n'))) {
2379 }
else if ((p = (
char*)strchr(buf,
'\r'))) {
2385 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"invalid header received with embedded nulls in "
2386 "Socket::readHTTPHeader()");
2391 if (!(t1 = (
char*)strstr(buf,
"HTTP/"))) {
2392 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"missing HTTP version string in "
2393 "first header line in Socket::readHTTPHeader()");
2400 int flags = CHF_PROCESS;
2407 flags |= CHF_HTTP11;
2413 const char* info_key;
2415 char* t2 = (
char*)strchr(buf + 8,
' ');
2418 if (isdigit(*(t2))) {
2420 if (strlen(t2) > 4) {
2427 info_key =
"response-uri";
2429 char* t2 = (
char*)strchr(buf,
' ');
2434 t1 = strchr(t2,
' ');
2442 info_key =
"request-uri";
2443 flags |= CHF_REQUEST;
2447 if (info || (event_queue && event_data)) {
2449 if (info && event_queue && event_data) {
2452 if (event_queue && event_data) {
2453 do_data_event_intern(QORE_EVENT_SOCKET_DATA_READ, source, **status_line);
2456 info->
setKeyValue(info_key, *status_line,
nullptr);
2458 status_line.release();
2461 bool close = convertHeaderToHash(*h, p, flags, info, &http_exp_chunked_body, headers_raw_key);
2462 do_read_http_header(QORE_EVENT_HTTP_MESSAGE_RECEIVED, *h, source);
2465 if ((flags & CHF_REQUEST) && info) {
2473 DLLLOCAL
int runHeaderCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2475 bool send_aborted =
false,
QoreObject* obj =
nullptr) {
2484 arg->
setKeyValue(
"send_aborted", send_aborted, xsink);
2485 args->push(arg,
nullptr);
2488 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2491 DLLLOCAL
int runTrailerCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2494 if (runCallback(xsink, cname, mname, rv, callback, l,
nullptr))
2497 switch (rv->getType()) {
2505 xsink->
raiseException(
"HTTP-TRAILER-ERROR",
"chunked callback returned type '%s'; expecting 'hash' "
2506 "or 'NOTHING'", rv->getTypeName());
2512 DLLLOCAL
int runDataCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2519 args->push(arg,
nullptr);
2522 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2538 return *xsink ? -1 : 0;
2541 DLLLOCAL
int sendHttpChunkedWithCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2543 bool* aborted =
nullptr) {
2545 assert(!aborted || !(*aborted));
2547 if (sock == QORE_INVALID_SOCKET) {
2548 se_not_open(cname, mname, xsink,
"sendHttpChunkedWithCallback");
2549 return QSE_NOT_OPEN;
2553 se_in_op(cname, mname, xsink);
2556 se_in_op_thread(cname, mname, xsink);
2560 PrivateQoreSocketThroughputHelper th(
this,
true);
2563 bool nb = (timeout_ms >= 0);
2565 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2569 qore_socket_op_helper oh(
this);
2578 bool data_available = tryReadSocketData(mname, xsink);
2580 if (data_available || *xsink) {
2582 return *xsink ? -1 : 0;
2588 rc = runCallback(xsink, cname, mname, res, send_callback, &l);
2597 const char* data_ptr =
nullptr;
2598 size_t data_size = 0;
2600 switch (res->getType()) {
2608 data_ptr = str->
c_str();
2609 data_size = str->
size();
2621 data_ptr =
static_cast<const char*
>(b->
getPtr());
2622 data_size = b->
size();
2634 const char* key = hi.getKey();
2641 do_header(key, buf, li.getValue());
2643 do_header(key, buf, v);
2654 xsink->
raiseException(
"SOCKET-CALLBACK-ERROR",
"HTTP chunked data callback returned type '%s'; expecting one of: 'string', 'binary', 'hash', 'nothing' (or 'NULL')", res->getTypeName());
2660 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2666 if (data_ptr && data_size) {
2667 rc = sendIntern(xsink, cname, mname, data_ptr, data_size, timeout_ms, total,
true);
2672 if (buf.
empty() && (!data_ptr || !data_size)) {
2673 buf.
set(
"0\r\n\r\n");
2677 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2683 switch (res->getType()) {
2686 if (!str->
empty()) {
2687 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *str);
2695 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *b);
2702 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, source, *h);
2710 if (aborted && *xsink) {
2711 bool data_available = tryReadSocketData(mname, xsink);
2713 if (data_available) {
2715 return *xsink ? -1 : 0;
2724 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2730 return rc < 0 || sock == QORE_INVALID_SOCKET ? -1 : 0;
2734 DLLLOCAL ssize_t sendIntern(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2735 int timeout_ms,
int64& total,
bool stream =
false) {
2741 bool nb = (timeout_ms >= 0);
2746 rc = ssl->write(mname, buf + bs, size - bs, timeout_ms, xsink);
2749 rc = ::send(sock, buf + bs, size - bs, 0);
2756 if (nb && (errno == EAGAIN
2758 || errno == EWOULDBLOCK
2761 if (!isWriteFinished(timeout_ms, mname, xsink)) {
2764 se_timeout(
"Socket", mname, timeout_ms, xsink);
2770 if (errno != EINTR) {
2772 xsink->
raiseErrnoException(
"SOCKET-SEND-ERROR", errno,
"error while executing %s::%s()", cname, mname);
2776 if (!stream && errno == EPIPE) {
2781 if (!stream && errno == ECONNRESET) {
2794 if (rc < 0 || sock == QORE_INVALID_SOCKET) {
2798 do_send_event(rc, bs, size);
2807 DLLLOCAL
int send(
int fd, ssize_t size,
int timeout_ms,
ExceptionSink* xsink);
2810 DLLLOCAL
int send(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2811 int timeout_ms = -1,
int source = QORE_SOURCE_SOCKET) {
2813 if (sock == QORE_INVALID_SOCKET) {
2814 se_not_open(cname, mname, xsink,
"send");
2815 return QSE_NOT_OPEN;
2819 se_in_op(cname, mname, xsink);
2822 se_in_op_thread(cname, mname, xsink);
2829 PrivateQoreSocketThroughputHelper th(
this,
true);
2832 bool nb = (timeout_ms >= 0);
2834 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2840 ssize_t rc = sendIntern(xsink, cname, mname, buf, size, timeout_ms, total);
2843 if (rc > 0 && source > 0) {
2844 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, buf, size);
2847 return rc < 0 || sock == QORE_INVALID_SOCKET ? rc : 0;
2852 if (sock == QORE_INVALID_SOCKET) {
2853 se_not_open(
"Socket",
"sendFromInputStream", xsink);
2858 se_in_op(
"Socket",
"sendFromInputStream", xsink);
2861 se_in_op_thread(
"Socket",
"sendFromInputStream", xsink);
2865 qore_socket_op_helper oh(
this);
2867 PrivateQoreSocketThroughputHelper th(
this,
true);
2870 bool nb = (timeout >= 0);
2872 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2876 char buf[DEFAULT_SOCKET_BUFSIZE];
2879 while (size < 0 || sent < size) {
2880 int64 toRead = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - sent, DEFAULT_SOCKET_BUFSIZE);
2884 r = is->
read(buf, toRead, xsink);
2893 xsink->
raiseException(
"SOCKET-SEND-ERROR",
"Unexpected end of stream");
2899 ssize_t rc = sendIntern(xsink,
"Socket",
"sendFromInputStream", buf, r, timeout, total);
2903 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, QORE_SOURCE_SOCKET, buf, r);
2910 if (sock == QORE_INVALID_SOCKET) {
2911 se_not_open(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2916 se_in_op(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2919 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2923 qore_socket_op_helper oh(
this);
2925 PrivateQoreSocketThroughputHelper th(
this,
true);
2928 bool nb = (timeout >= 0);
2930 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2936 buf->preallocate(max_chunk_size);
2942 r = is->
read((
void*)buf->getPtr(),
sizeof(max_chunk_size), xsink);
2949 str.
sprintf(
"%x\r\n", (
int)r);
2950 int rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2954 bool trailers =
false;
2958 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", (
const char*)buf->getPtr(), r, timeout, total,
true);
2961 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, QORE_SOURCE_SOCKET, buf->getPtr(), r);
2962 }
else if (trailer_callback) {
2966 if (runTrailerCallback(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", *trailer_callback, l, h))
2970 do_headers(str, *h, 0,
false);
2972 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2976 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, **h);
2984 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2998 if (sock == QORE_INVALID_SOCKET) {
2999 se_not_open(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3004 se_in_op(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3007 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3017 const char* key = hi.getKey();
3022 do_header(key, buf, li.getValue());
3025 do_header(key, buf, v);
3030 sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyTrailer", buf.
getBuffer(), buf.
size(), timeout, total,
true);
3032 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, *headers);
3036 DLLLOCAL
void getSendHttpMessageHeaders(
QoreString& hdr,
QoreHashNode* info,
const char* method,
const char* path,
3037 const char* http_version,
const QoreHashNode* headers,
size_t size,
int source) {
3039 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3046 getSendHttpMessageHeadersCommon(hdr, info, headers, size, source);
3050 size_t size,
int source) {
3052 do_send_http_message_event(hdr, headers, source);
3057 do_headers(hdr, headers, size);
3061 const char* method,
const char* path,
const char* http_version,
const QoreHashNode* headers,
3069 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
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);
3089 hdr.
sprintf(
"HTTP/%s %03d %s", http_version, code, desc);
3097 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3098 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3107 assert(!(data && send_callback));
3108 assert(!(data && input_stream));
3109 assert(!(send_callback && input_stream));
3112 do_send_http_message_event(hdr, headers, source);
3117 do_headers(hdr, headers, size && data ? size : 0);
3123 if ((rc = send(xsink, cname, mname, hdr.
c_str(), hdr.
size(), timeout_ms, -1)))
3128 int rc = send(xsink, cname, mname, (
char*)data, size, timeout_ms, -1);
3131 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, *body);
3133 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, data, size);
3137 }
else if (send_callback) {
3139 assert(!aborted || !(*aborted));
3140 return sendHttpChunkedWithCallback(xsink, cname, mname, *send_callback, *l, source, timeout_ms, aborted);
3141 }
else if (input_stream) {
3143 sendHttpChunkedBodyFromInputStream(input_stream, max_chunk_size, timeout_ms, xsink, l, trailer_callback);
3144 return *xsink ? -1 : 0;
3153 if (sock == QORE_INVALID_SOCKET) {
3154 se_not_open(cname,
"readHTTPChunkedBodyBinary", xsink);
3159 se_in_op(cname,
"readHTTPChunkedBodyBinary", xsink);
3162 se_in_op_thread(cname,
"readHTTPChunkedBodyBinary", xsink);
3167 if (http_exp_chunked_body)
3168 http_exp_chunked_body =
false;
3170 qore_socket_op_helper oh(
this);
3183 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 1, 0, timeout,
false);
3187 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3194 if (!state && c ==
'\r')
3196 else if (state && c ==
'\n')
3210 char* p = (
char*)strchr(str.
getBuffer(),
';');
3213 long size = strtol(str.
c_str(), 0, 16);
3214 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
size(), source);
3220 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3227 ssize_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3231 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, bs, 0, timeout,
false);
3236 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3241 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, buf, (
size_t)rc);
3245 os->
write(buf, rc, xsink);
3267 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 2 - br, 0, timeout,
false);
3271 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3278 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3280 if (recv_callback && !os) {
3281 if (runDataCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, *b,
true))
3297 if (!recv_callback && !os) {
3305 return recv_callback ? 0 : h.release();
3307 if (recv_callback) {
3310 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3311 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3314 if (recv_callback) {
3315 runHeaderCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, h->
empty() ?
nullptr : *h,
3316 info.release(),
false, obj);
3327 if (sock == QORE_INVALID_SOCKET) {
3328 se_not_open(cname,
"readHTTPChunkedBody", xsink);
3333 se_in_op(cname,
"readHTTPChunkedBody", xsink);
3336 se_in_op_thread(cname,
"readHTTPChunkedBody", xsink);
3341 if (http_exp_chunked_body)
3342 http_exp_chunked_body =
false;
3344 qore_socket_op_helper oh(
this);
3357 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 1, 0, timeout,
false);
3361 se_closed(cname,
"readHTTPChunkedBody", xsink);
3368 if (!state && c ==
'\r')
3370 else if (state && c ==
'\n')
3384 char* p = (
char*)strchr(str.
getBuffer(),
';');
3387 ssize_t size = strtol(str.
getBuffer(), 0, 16);
3388 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
strlen(), source);
3394 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3404 ssize_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3409 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, bs, 0, timeout,
false);
3413 se_closed(cname,
"readHTTPChunkedBody", xsink);
3419 buf->concat(tbuf, rc);
3421 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, tbuf, (
size_t)rc);
3437 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 2 - br, 0, timeout,
false);
3441 se_closed(cname,
"readHTTPChunkedBody", xsink);
3448 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3450 if (recv_callback) {
3451 if (runDataCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, *buf,
true))
3464 if (!recv_callback) {
3472 return recv_callback ? 0 : h.release();
3474 if (recv_callback) {
3477 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3478 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3481 if (recv_callback) {
3482 runHeaderCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, h->
empty() ?
nullptr : *h,
3483 info.release(),
false, obj);
3490 DLLLOCAL
static void do_accept_encoding(
char* t,
QoreHashNode& info) {
3499 while (*a && *a !=
';' && *a !=
',')
3503 l->push(str.release(),
nullptr);
3513 info.
setKeyValue(
"accept-encoding", l.release(), 0);
3516 DLLLOCAL
bool do_accept_charset(
char* t,
QoreHashNode& info) {
3517 bool acceptcharset =
false;
3532 if (*a ==
'u' || *a ==
'U') {
3534 if (*a ==
't' || *a ==
'T') {
3536 if (*a ==
'f' || *a ==
'F') {
3548 }
else if (*a ==
',') {
3552 }
else if (*a ==
';') {
3561 acceptcharset =
true;
3565 ac->concat(t, div - t);
3570 info.
setKeyValue(
"accept-charset", ac.release(), 0);
3571 acceptcharset =
true;
3575 return acceptcharset;
3580 bool* chunked =
nullptr,
const char* headers_raw_key =
"headers-raw") {
3581 bool close = !(flags & CHF_HTTP11);
3583 const char* senc =
nullptr;
3585 bool acceptcharset =
false;
3593 std::string raw_key;
3598 if ((p = strstr(buf,
"\r\n"))) {
3601 }
else if ((p = strchr(buf,
'\n'))) {
3604 }
else if ((p = strchr(buf,
'\r'))) {
3609 char* t = strchr(buf,
':');
3614 while (t && qore_isblank(*t))
3624 if (flags & CHF_PROCESS) {
3625 if (!strcmp(buf,
"connection")) {
3626 if (flags & CHF_HTTP11) {
3627 if (strcasestr(t,
"close"))
3630 if (strcasestr(t,
"keep-alive"))
3633 }
else if (!strcmp(buf,
"content-type")) {
3634 char* a = strcasestr(t,
"charset=");
3637 char* e = strchr(a + 8,
';');
3641 cs.
concat(a + 8, e - a - 8);
3650 size_t len = cs.
size();
3660 }
while (a > t && (*a ==
' ' || *a ==
';'));
3667 ct->concat(t, a - t + 1);
3673 info->
setKeyValue(
"body-content-type", ct.release(),
nullptr);
3679 info->
setKeyValue(
"body-content-type", val->refSelf(),
nullptr);
3682 }
else if (chunked && !strcmp(buf,
"transfer-encoding") && !strcasecmp(t,
"chunked")) {
3685 if (!strcmp(buf,
"accept-charset"))
3686 acceptcharset = do_accept_charset(t, *info);
3687 else if ((flags & CHF_REQUEST) && !strcmp(buf,
"accept-encoding"))
3688 do_accept_encoding(t, *info);
3693 if (raw_hdr && val) {
3694 val_copy = val->realCopy();
3698 hash_assignment_priv ha(*h, buf);
3699 if (!(*ha).isNothing()) {
3701 if ((*ha).getType() ==
NT_LIST) {
3705 l->
push(ha.swap(l),
nullptr);
3707 l->
push(val.release(),
nullptr);
3709 ha.assign(val.release(), 0);
3713 hash_assignment_priv ha(*raw_hdr, raw_key);
3714 if (!(*ha).isNothing()) {
3716 if ((*ha).getType() ==
NT_LIST) {
3720 l->
push(ha.swap(l),
nullptr);
3722 l->
push(val_copy.release(),
nullptr);
3724 ha.assign(val_copy.release(),
nullptr);
3728 if ((flags & CHF_PROCESS)) {
3732 if (info && !acceptcharset)
3739 DLLLOCAL
int recvix(
const char* meth,
int len,
void* targ,
int timeout_ms,
ExceptionSink* xsink) {
3741 if (sock == QORE_INVALID_SOCKET) {
3742 se_not_open(
"Socket", meth, xsink,
"recvix");
3743 return QSE_NOT_OPEN;
3747 se_in_op(
"Socket", meth, xsink);
3750 se_in_op_thread(
"Socket", meth, xsink);
3754 PrivateQoreSocketThroughputHelper th(
this,
false);
3759 ssize_t rc = brecv(xsink, meth, buf, len - br, 0, timeout_ms);
3761 do_read_error(rc, meth, timeout_ms, xsink);
3765 memcpy(targ, buf, rc);
3773 do_data_event(QORE_EVENT_SOCKET_DATA_READ, QORE_SOURCE_SOCKET, targ, br);
3779 if (warn_callback_arg) {
3780 warn_callback_arg.
discard(xsink);
3783 warn_queue->deref(xsink);
3784 warn_queue =
nullptr;
3786 tp_warning_bs = 0.0;
3792 int64 min_ms = 1000) {
3795 if (warning_ms <= 0 && warning_bs <= 0) {
3796 xsink->
raiseException(
"SOCKET-SETWARNINGQUEUE-ERROR",
"Socket::setWarningQueue() at least one of warning "
3797 "ms argument: " QLLD
" and warning B/s argument: " QLLD
" must be greater than zero; to clear, call "\
3798 "Socket::clearWarningQueue() with no arguments", warning_ms, warning_bs);
3808 warn_queue->
deref(xsink);
3809 warn_callback_arg.
discard(xsink);
3812 warn_queue = qholder.release();
3813 warn_callback_arg = holder.release();
3814 tl_warning_us = (
int64)warning_ms * 1000;
3815 tp_warning_bs = warning_bs;
3816 tp_us_min = min_ms * 1000;
3819 DLLLOCAL
void getUsageInfo(
QoreHashNode& h, qore_socket_private& s)
const {
3827 h.
setKeyValue(
"bytes_sent", tp_bytes_sent + s.tp_bytes_sent, 0);
3828 h.
setKeyValue(
"bytes_recv", tp_bytes_recv + s.tp_bytes_sent, 0);
3829 h.
setKeyValue(
"us_sent", tp_us_sent + s.tp_us_sent, 0);
3830 h.
setKeyValue(
"us_recv", tp_us_recv + s.tp_us_recv, 0);
3853 DLLLOCAL
void clearStats() {
3860 DLLLOCAL
void doTimeoutWarning(
const char* op,
int64 dt) {
3862 assert(dt > tl_warning_us);
3870 if (warn_callback_arg)
3873 warn_queue->pushAndTakeRef(h);
3876 DLLLOCAL
void doThroughputWarning(
bool send,
int64 bytes,
int64 dt,
double bs) {
3878 assert(bs < tp_warning_bs);
3888 if (warn_callback_arg)
3891 warn_queue->pushAndTakeRef(h);
3894 DLLLOCAL
bool pendingHttpChunkedBody()
const {
3895 return http_exp_chunked_body && sock != QORE_INVALID_SOCKET;
3898 DLLLOCAL
void setSslVerifyMode(
int mode) {
3900 ssl_verify_mode = mode;
3902 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3905 DLLLOCAL
void acceptAllCertificates(
bool accept_all =
true) {
3906 ssl_accept_all_certs = accept_all;
3908 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3913 ssl_err_str->
concat(
"; ");
3914 ssl_err_str->
concat(err_str);
3917 ssl_err_str = err_str;
3922 sock.priv->getUsageInfo(h, *s.priv);
3925 DLLLOCAL
static qore_socket_private* get(
QoreSocket& sock) {
3929 DLLLOCAL
static const qore_socket_private* get(
const QoreSocket& sock) {
3933 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
DLLEXPORT QoreStringNode * q_strerror(int errnum)
returns the error string as a QoreStringNode
#define QORE_MIN(a, b)
macro to return the minimum of 2 numbers
Definition: QoreLib.h:616
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:594
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:50
DLLEXPORT int appendLastDescription(const char *fmt,...)
appends a formatted string to the top exception description if the desc value is a string
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...
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 ...
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
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,...
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)
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:51
DLLEXPORT int setKeyValue(const char *key, QoreValue value, ExceptionSink *xsink)
sets the value of "key" to "value"
DLLEXPORT QoreHashNode * hashRefSelf() const
returns "this" with an incremented reference count
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
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:61
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
represents an X509 certificate, reference-counted, dynamically-allocated only
Definition: QoreSSLCertificate.h:42
provides access to a private key data structure for SSL connections
Definition: QoreSSLPrivateKey.h:40
DLLEXPORT double getAsFloat() const
returns the value as a float
DLLLOCAL detail::QoreValueCastHelper< T >::Result get()
returns the value as the given type
Definition: QoreValue.h:214
DLLEXPORT qore_type_t getType() const
returns the type of value contained
DLLEXPORT bool getAsBool() const
returns the value as a bool
DLLEXPORT int64 getAsBigInt() const
returns the value as an int
DLLEXPORT void clear()
unconditionally set the QoreValue to QoreNothingNode (does not dereference any possible contained Abs...
provides access to sockets using Qore data structures
Definition: QoreSocket.h:129
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 const char * c_str() const
returns the string's buffer; this data should not be changed
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 char * giveBuffer()
returns the character buffer and leaves the QoreString empty, the caller owns the memory returned (mu...
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
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 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
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
a templated class to manage a reference count of an object that can throw a Qore-language exception w...
Definition: ReferenceHolder.h:52
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
manages a reference count of a pointer to a class that takes a simple "deref()" call with no argument...
Definition: ReferenceHolder.h:127
a helper class for getting socket origination information
Definition: QoreSocket.h:76
holds an object and dereferences it in the destructor
Definition: QoreValue.h:487
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
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:279
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