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");
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, X509* cert, EVP_PKEY* pkey);
327 qore_socket_private* sock;
334class SocketAcceptPollState :
public AbstractPollState {
336 DLLLOCAL SocketAcceptPollState(
ExceptionSink* xsink, qore_socket_private* sock);
338 qore_socket_private* sock;
341class SocketAcceptSslPollState :
public AbstractPollState {
342 DLLLOCAL SocketAcceptSslPollState(
ExceptionSink* xsink, qore_socket_private* sock, X509* cert, EVP_PKEY* pkey)
345 SSLSocketHelperHelper sshh(sock,
true);
347 sock->do_start_ssl_event();
349 if (rc = sock->ssl->setServer(
"acceptSSL", sock->sock, cert, pkey, xsink)) {
355 ssl->startAccept(xsink);
360class SocketSendPollState :
public AbstractPollState {
362 DLLLOCAL SocketSendPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* data,
size_t size);
373 qore_socket_private* sock;
379class SocketRecvPollState :
public AbstractPollState {
381 DLLLOCAL SocketRecvPollState(
ExceptionSink* xsink, qore_socket_private* sock,
size_t size);
392 DLLLOCAL
virtual QoreValue takeOutput() {
399 qore_socket_private* sock;
405class SocketRecvUntilBytesPollState :
public AbstractPollState {
407 DLLLOCAL SocketRecvUntilBytesPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* bytes,
419 DLLLOCAL
virtual QoreValue takeOutput() {
420 size_t len = bin->size();
427 qore_socket_private* sock;
438hashdecl qore_socket_private {
439 friend class PrivateQoreSocketTimeoutHelper;
440 friend class PrivateQoreSocketThroughputHelper;
441 friend class SocketConnectInetPollState;
444 static thread_local qore_socket_private* current_socket;
446 int sock, sfamily, port, stype, sprot;
449 int64 connection_id = 0;
453 std::string socketname;
455 std::string client_target;
456 SSLSocketHelper* ssl =
nullptr;
457 Queue* event_queue =
nullptr,
458 * warn_queue =
nullptr;
461 std::string assume_http_encoding =
"ISO-8859-1";
464 char rbuf[DEFAULT_SOCKET_BUFSIZE];
470 int64 tl_warning_us = 0;
471 double tp_warning_bs = 0;
472 int64 tp_bytes_sent = 0,
484 http_exp_chunked_body =
false,
485 ssl_accept_all_certs =
false,
486 ssl_capture_remote_cert =
false,
489 ssl_verify_mode = SSL_VERIFY_NONE;
497 DLLLOCAL qore_socket_private(
int n_sock = QORE_INVALID_SOCKET,
int n_sfamily = AF_UNSPEC,
499 sock(n_sock), sfamily(n_sfamily), port(-1), stype(n_stype), sprot(n_prot), enc(n_enc) {
502 DLLLOCAL ~qore_socket_private() {
506 assert(!event_queue);
510 DLLLOCAL
bool isOpen() {
511 return sock != QORE_INVALID_SOCKET;
514 DLLLOCAL
int close() {
515 int rc = close_internal();
518 if (http_exp_chunked_body)
519 http_exp_chunked_body =
false;
527 DLLLOCAL
int close_and_reset() {
528 assert(sock != QORE_INVALID_SOCKET);
532 rc = ::closesocket(sock);
537 if (!rc || sock_get_error() != EINTR)
541 sock = QORE_INVALID_SOCKET;
551 client_target.clear();
555 DLLLOCAL
int close_internal() {
558 ssl_err_str->deref();
559 ssl_err_str =
nullptr;
562 remote_cert->
deref(
nullptr);
563 remote_cert =
nullptr;
573 if (!socketname.empty()) {
575 unlink(socketname.c_str());
583 return close_and_reset();
589 DLLLOCAL
void setAssumedEncoding(
const char* str) {
590 assume_http_encoding = str;
593 DLLLOCAL
const char* getAssumedEncoding()
const {
594 return assume_http_encoding.c_str();
597 DLLLOCAL
int getSendTimeout()
const {
600#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
603 int size =
sizeof(
hashdecl timeval);
605 socklen_t size =
sizeof(
hashdecl timeval);
608 if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
611 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
614 DLLLOCAL
int getRecvTimeout()
const {
617#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
620 int size =
sizeof(
hashdecl timeval);
622 socklen_t size =
sizeof(
hashdecl timeval);
625 if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
628 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
631 DLLLOCAL
int getPort() {
633 if (sock == QORE_INVALID_SOCKET || (sfamily != AF_INET && sfamily != AF_INET6) || port > 0)
637 hashdecl sockaddr_storage addr;
638#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
640 int size =
sizeof addr;
642 socklen_t size =
sizeof addr;
645 if (getsockname(sock, (
struct sockaddr *)&addr, (socklen_t *)&size) < 0)
648 port = q_get_port_from_addr((
const struct sockaddr *)&addr);
662 size_t offset = hdr.
size();
667 q_fix_decimal(&hdr, offset);
684 DLLLOCAL
static void do_headers(
QoreString& hdr,
const QoreHashNode* headers,
size_t size,
bool addsize =
true) {
692 const char* key = hi.getKey();
693 if (addsize && !strcasecmp(key,
"transfer-encoding"))
695 if ((addsize || size) && !strcasecmp(key,
"content-length")) {
702 do_header(key, hdr, li.getValue());
704 do_header(key, hdr, v);
708 if (size || addsize) {
709 hdr.
sprintf(
"Content-Length: %zu\r\n", size);
716 DLLLOCAL
int listen(
int backlog = 20) {
717 if (sock == QORE_INVALID_SOCKET)
722 if (::listen(sock, backlog)) {
729 return ::listen(sock, backlog);
733 DLLLOCAL
int accept_intern(
ExceptionSink* xsink,
struct sockaddr *addr, socklen_t *size,
int timeout_ms = -1) {
737 if (timeout_ms >= 0 && !isDataAvailable(timeout_ms,
"accept", xsink)) {
744 int rc = ::accept(sock, addr, size);
745 if (rc != QORE_INVALID_SOCKET)
749 if (sock_get_error() == EINTR)
752 qore_socket_error(xsink,
"SOCKET-ACCEPT-ERROR",
"error in accept()", 0, 0, 0, addr);
760 if (sock == QORE_INVALID_SOCKET) {
761 xsink->
raiseException(
"SOCKET-NOT-OPEN",
"socket must be opened, bound, and in a listening state before "
762 "new connections can be accepted");
767 se_in_op(
"Socket",
"accept", xsink);
770 se_in_op_thread(
"Socket",
"accept", xsink);
771 return QSE_IN_OP_THREAD;
775 if (sfamily == AF_UNIX) {
777 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"UNIX sockets are not available under Windows");
780 hashdecl sockaddr_un addr_un;
782#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
785 int size =
sizeof(
hashdecl sockaddr_un);
787 socklen_t size =
sizeof(
hashdecl sockaddr_un);
789 rc = accept_intern(xsink, (
struct sockaddr *)&addr_un, (socklen_t *)&size, timeout_ms);
792 if (rc >= 0 && source) {
794 addr->
sprintf(
"UNIX socket: %s", socketname.c_str());
795 source->priv->setAddress(addr);
796 source->priv->setHostName(
"localhost");
799 }
else if (sfamily == AF_INET || sfamily == AF_INET6) {
800 hashdecl sockaddr_storage addr_in;
801#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
804 int size =
sizeof(addr_in);
806 socklen_t size =
sizeof(addr_in);
809 rc = accept_intern(xsink, (
struct sockaddr *)&addr_in, (socklen_t *)&size, timeout_ms);
812 if (rc >= 0 && source) {
813 char host[NI_MAXHOST + 1];
814 char service[NI_MAXSERV + 1];
816 if (!getnameinfo((
struct sockaddr *)&addr_in, qore_get_in_len((
struct sockaddr *)&addr_in), host,
sizeof(host), service,
sizeof(service), NI_NUMERICSERV)) {
817 source->priv->setHostName(host);
821 char ifname[INET6_ADDRSTRLEN];
822 if (inet_ntop(addr_in.ss_family, qore_get_in_addr((
struct sockaddr *)&addr_in), ifname,
sizeof(ifname))) {
824 source->priv->setAddress(ifname);
829 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"do not know how to accept connections with address family %d", sfamily);
835 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_SOCKET)
const {
854 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
857 event_queue->deref(xsink);
858 event_queue =
nullptr;
861 warn_queue->deref(xsink);
862 warn_queue =
nullptr;
863 if (warn_callback_arg) {
864 warn_callback_arg.
discard(xsink);
865 warn_callback_arg.
clear();
875 event_queue->deref(xsink);
879 event_data = with_data;
882 DLLLOCAL
void do_start_ssl_event() {
884 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_START_SSL));
888 DLLLOCAL
void do_ssl_established_event() {
893 event_queue->pushAndTakeRef(h);
897 DLLLOCAL
void do_connect_event(
int af,
const struct sockaddr* addr,
const char* target,
const char* service =
nullptr,
int prt = -1) {
906 q_af_to_hash(af, *h,
nullptr);
912 event_queue->pushAndTakeRef(h);
916 DLLLOCAL
void do_connected_event() {
918 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CONNECTED));
922 DLLLOCAL
void do_data_event_intern(
int event,
int source,
const QoreStringNode& str)
const {
923 assert(event_queue && event_data && str.
size());
926 event_queue->pushAndTakeRef(h.release());
929 DLLLOCAL
void do_data_event(
int event,
int source,
const QoreStringNode& str)
const {
930 if (event_queue && event_data && str.
size()) {
931 do_data_event_intern(event, source, str);
935 DLLLOCAL
void do_data_event(
int event,
int source,
const BinaryNode& b)
const {
936 if (event_queue && event_data && b.
size()) {
939 event_queue->pushAndTakeRef(h.release());
943 DLLLOCAL
void do_data_event(
int event,
int source,
const void* data,
size_t size)
const {
944 if (event_queue && event_data && size) {
949 event_queue->pushAndTakeRef(h.release());
953 DLLLOCAL
void do_header_event(
int event,
int source,
const QoreHashNode& hdr)
const {
954 if (event_queue && event_data && !hdr.
empty()) {
957 event_queue->pushAndTakeRef(h.release());
961 DLLLOCAL
void do_chunked_read(
int event,
size_t bytes,
size_t total_read,
int source) {
964 if (event == QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED)
969 event_queue->pushAndTakeRef(h);
973 DLLLOCAL
void do_read_http_header(
int event,
const QoreHashNode* headers,
int source) {
977 event_queue->pushAndTakeRef(h);
981 DLLLOCAL
void do_send_http_message_event(
const QoreString& str,
const QoreHashNode* headers,
int source) {
983 QoreHashNode* h = getEvent(QORE_EVENT_HTTP_SEND_MESSAGE, source);
987 event_queue->pushAndTakeRef(h);
991 DLLLOCAL
void do_close_event() {
993 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
997 DLLLOCAL
void do_read_event(
size_t bytes_read,
size_t total_read,
size_t bufsize = 0,
int source = QORE_SOURCE_SOCKET) {
1000 QoreHashNode* h = getEvent(QORE_EVENT_PACKET_READ, source);
1002 h->
setKeyValue(
"total_read", total_read,
nullptr);
1005 h->
setKeyValue(
"total_to_read", bufsize,
nullptr);
1006 event_queue->pushAndTakeRef(h);
1010 DLLLOCAL
void do_send_event(
int bytes_sent,
int total_sent,
int bufsize) {
1015 h->
setKeyValue(
"total_sent", total_sent,
nullptr);
1016 h->
setKeyValue(
"total_to_send", bufsize,
nullptr);
1017 event_queue->pushAndTakeRef(h);
1021 DLLLOCAL
void do_resolve_event(
const char* host,
const char* service = 0) {
1024 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_LOOKUP);
1029 event_queue->pushAndTakeRef(h);
1033 DLLLOCAL
void do_resolved_event(
const struct sockaddr* addr) {
1036 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_RESOLVED);
1042 int prt = q_get_port_from_addr(addr);
1045 q_af_to_hash(addr->sa_family, *h,
nullptr);
1046 event_queue->pushAndTakeRef(h);
1050 DLLLOCAL
int64 getObjectIDForEvents()
const {
1054 DLLLOCAL
int connectUNIX(
const char* p,
int sock_type,
int protocol,
ExceptionSink* xsink) {
1057 QORE_TRACE(
"connectUNIX()");
1060 xsink->
raiseException(
"SOCKET-CONNECTUNIX-ERROR",
"UNIX sockets are not available under Windows");
1066 printd(5,
"qore_socket_private::connectUNIX(%s)\n", p);
1068 hashdecl sockaddr_un addr;
1070 addr.sun_family = AF_UNIX;
1072 strncpy(addr.sun_path, p,
sizeof(addr.sun_path) - 1);
1073 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1074 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_SOCKET_ERROR) {
1075 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"error connecting to UNIX socket: '%s'", p);
1079 do_connect_event(AF_UNIX, (sockaddr*)&addr, p);
1081 if (!::connect(sock, (
const sockaddr *)&addr,
sizeof(
struct sockaddr_un)))
1085 if (sock_get_error() == EINTR)
1091 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, p);
1097 socketname = addr.sun_path;
1100 do_connected_event();
1112 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
const char* cname,
const char* mname,
1115 assert(read || write);
1116 if (sock == QORE_INVALID_SOCKET) {
1117 se_not_open(cname, mname, xsink,
"asyncIoWait");
1121 return asyncIoWait(timeout_ms, read, write, xsink);
1124 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
ExceptionSink* xsink)
const {
1126#if defined HAVE_POLL
1127 return poll_intern(xsink, timeout_ms, read, write);
1128#elif defined HAVE_SELECT
1129 return select_intern(xsink, timeout_ms, read, write);
1131#error no async socket operations supported
1135#if defined HAVE_POLL
1136 DLLLOCAL
int poll_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1143 pollfd fds = {sock, arg, 0};
1145 rc = ::poll(&fds, 1, timeout_ms);
1146 if (rc == -1 && errno == EINTR)
1151 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"poll(2) returned an error");
1152 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
1157#elif defined HAVE_SELECT
1158 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1159 bool aborted =
false;
1160 int rc = select_intern(xsink, timeout_ms, read, write, aborted);
1161 if (rc != QORE_SOCKET_ERROR && aborted)
1166 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write,
bool& aborted)
const {
1173 if (sock >= FD_SETSIZE) {
1174 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);
1178 hashdecl timeval tv;
1189 tv.tv_sec = timeout_ms / 1000;
1190 tv.tv_usec = (timeout_ms % 1000) * 1000;
1192 fd_set* readfd = read ? &sfs : 0;
1193 fd_set* writefd = write ? &sfs : 0;
1195 rc = select(sock + 1, readfd, writefd, &err, &tv);
1197 if (rc != QORE_SOCKET_ERROR) {
1198 if (FD_ISSET(sock, &err))
1202 if (sock_get_error() != EINTR)
1205 if (rc == QORE_SOCKET_ERROR) {
1208 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"select(2) returned an error");
1215 DLLLOCAL
bool tryReadSocketData(
const char* mname,
ExceptionSink* xsink) {
1220 return asyncIoWait(0,
true,
false,
"Socket", mname, xsink);
1224 int rc = ssl->doSSLRW(xsink, mname, rbuf, 1, 0, PEEK,
false);
1225 if (*xsink || (rc == QSE_TIMEOUT)) {
1228 return rc > 0 ? true :
false;
1231 DLLLOCAL
bool isSocketDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1232 return asyncIoWait(timeout_ms,
true,
false,
"Socket", mname, xsink);
1235 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1238 return isSocketDataAvailable(timeout_ms, mname, xsink);
1241 DLLLOCAL
bool isWriteFinished(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1242 return asyncIoWait(timeout_ms,
false,
true,
"Socket", mname, xsink);
1245 DLLLOCAL
int close_and_exit() {
1246 if (sock != QORE_INVALID_SOCKET)
1251 DLLLOCAL
int connectINETTimeout(
int timeout_ms,
const struct sockaddr* ai_addr,
size_t ai_addrlen,
1254 PrivateQoreSocketTimeoutHelper toh(
this,
"connect");
1257 if (!::connect(sock, ai_addr, ai_addrlen))
1261 if (sock_get_error() != EAGAIN) {
1262 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1270 if (errno != EINPROGRESS)
1279 bool aborted =
false;
1280 int rc = select_intern(xsink, timeout_ms,
false,
true, aborted);
1287 if (rc != QORE_SOCKET_ERROR && aborted) {
1288 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1292 int rc = asyncIoWait(timeout_ms,
false,
true,
"Socket",
"connectINETTimeout", xsink);
1298 if (rc == QORE_SOCKET_ERROR && sock_get_error() != EINTR) {
1300 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in asyncIoWait() with "
1301 "Socket::connect() with timeout", 0, 0, 0, ai_addr);
1303 }
else if (rc > 0) {
1304 return checkConnected(xsink,
nullptr, ai_addr, only_timeout);
1308 concat_target(*(*desc), ai_addr);
1318 DLLLOCAL
int checkConnected(
ExceptionSink* xsink,
const char* hostsvc,
const struct sockaddr* ai_addr =
nullptr,
1319 bool only_timeout =
false) {
1323 socklen_t lon =
sizeof(int);
1326 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (GETSOCKOPT_ARG_4)(&val), &lon) == QORE_SOCKET_ERROR) {
1327 if (!only_timeout) {
1328 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
nullptr,
1339 qore_socket_error_intern(val, xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
1348 DLLLOCAL
void confirmConnected(
const char* host) {
1349 do_connected_event();
1353 client_target = host;
1357 DLLLOCAL
int sock_errno_err(
const char* err,
const char* desc,
ExceptionSink* xsink) {
1359 qore_socket_error(xsink, err, desc);
1363 DLLLOCAL
int set_non_blocking(
bool non_blocking,
ExceptionSink* xsink) {
1366 if (sock == QORE_INVALID_SOCKET) {
1372 u_long mode = non_blocking ? 1 : 0;
1373 int rc = ioctlsocket(sock, FIONBIO, &mode);
1374 if (check_windows_rc(rc)) {
1375 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in ioctlsocket(FIONBIO)", xsink);
1381 if ((arg = fcntl(sock, F_GETFL, 0)) < 0) {
1382 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() getting socket descriptor status "
1392 if (fcntl(sock, F_SETFL, arg) < 0) {
1393 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() setting socket descriptor status "
1402 DLLLOCAL
int connectINET(
const char* host,
const char* service,
int timeout_ms,
ExceptionSink* xsink,
1403 int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0) {
1405 family = q_get_af(family);
1406 type = q_get_sock_type(type);
1408 QORE_TRACE(
"qore_socket_private::connectINET()");
1413 printd(5,
"qore_socket_private::connectINET(%s:%s, %dms)\n", host, service, timeout_ms);
1415 do_resolve_event(host, service);
1418 if (ai.
getInfo(xsink, host, service, family, 0, type, protocol))
1425 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1426 do_resolved_event(p->ai_addr);
1428 int prt = q_get_port_from_addr(aip->ai_addr);
1430 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1431 if (!connectINETIntern(host, service, p->ai_family, p->ai_addr, p->ai_addrlen, p->ai_socktype,
1432 p->ai_protocol, prt, timeout_ms, xsink,
true)) {
1441 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1446 DLLLOCAL
int connectINETIntern(
const char* host,
const char* service,
int ai_family,
struct sockaddr* ai_addr,
1447 size_t ai_addrlen,
int ai_socktype,
int ai_protocol,
int prt,
int timeout_ms,
ExceptionSink* xsink,
1448 bool only_timeout =
false) {
1450 printd(5,
"qore_socket_private::connectINETIntern() host: %s service: %s family: %d timeout_ms: %d\n", host,
1451 service, ai_family, timeout_ms);
1452 if ((sock = socket(ai_family, ai_socktype, ai_protocol)) == QORE_INVALID_SOCKET) {
1453 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"cannot establish a connection to %s:%s", host,
1464 if (timeout_ms >= 0) {
1466 if (set_non_blocking(
true, xsink))
1467 return close_and_exit();
1469 do_connect_event(ai_family, ai_addr, host, service, prt);
1471 rc = connectINETTimeout(timeout_ms, ai_addr, ai_addrlen, xsink, only_timeout);
1475 if (set_non_blocking(
false, xsink))
1476 return close_and_exit();
1478 do_connect_event(ai_family, ai_addr, host, service, prt);
1481 rc = ::connect(sock, ai_addr, ai_addrlen);
1484 if (!rc || sock_get_error() != EINTR)
1490 if (!only_timeout || errno == ETIMEDOUT)
1491 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1493 return close_and_exit();
1496 sfamily = ai_family;
1497 stype = ai_socktype;
1498 sprot = ai_protocol;
1503 confirmConnected(host);
1507 DLLLOCAL
int upgradeClientToSSLIntern(
const char* mname,
const char* sni_target_host, X509* cert, EVP_PKEY* pkey,
1510 SSLSocketHelperHelper sshh(
this,
true);
1513 do_start_ssl_event();
1515 if (!sni_target_host && !client_target.empty()) {
1516 sni_target_host = client_target.c_str();
1518 if ((rc = ssl->setClient(mname, sni_target_host, sock, cert, pkey, xsink)) || ssl->connect(mname, timeout_ms,
1521 return rc ? rc : -1;
1523 do_ssl_established_event();
1528 DLLLOCAL
int upgradeServerToSSLIntern(
const char* mname, X509* cert, EVP_PKEY* pkey,
int timeout_ms,
1532 SSLSocketHelperHelper sshh(
this,
true);
1534 do_start_ssl_event();
1535 if (ssl->setServer(mname, sock, cert, pkey, xsink) || ssl->accept(mname, timeout_ms, xsink)) {
1539 do_ssl_established_event();
1545 DLLLOCAL
int openUNIX(
int sock_type = SOCK_STREAM,
int protocol = 0) {
1546 if (sock != QORE_INVALID_SOCKET)
1549 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_INVALID_SOCKET) {
1561 DLLLOCAL
int openINET(
int family = AF_INET,
int sock_type = SOCK_STREAM,
int protocol = 0) {
1562 if (sock != QORE_INVALID_SOCKET)
1565 if ((sock = socket(family, sock_type, protocol)) == QORE_INVALID_SOCKET)
1575 DLLLOCAL
int reuse(
int opt) {
1577 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_ARG_4)&opt,
sizeof(
int));
1581 DLLLOCAL
int bindIntern(
struct sockaddr* ai_addr,
size_t ai_addrlen,
int prt,
bool reuseaddr,
ExceptionSink* xsink = 0) {
1584 if ((::bind(sock, ai_addr, ai_addrlen)) == QORE_SOCKET_ERROR) {
1586 qore_socket_error(xsink,
"SOCKET-BIND-ERROR",
"error in bind()", 0, 0, 0, ai_addr);
1596#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1598 int len = ai_addrlen;
1600 socklen_t len = ai_addrlen;
1603 if (getsockname(sock, ai_addr, &len))
1606 port = q_get_port_from_addr(ai_addr);
1612 DLLLOCAL
int bindUNIX(
ExceptionSink* xsink,
const char* name,
int socktype = SOCK_STREAM,
int protocol = 0) {
1615 xsink->
raiseException(
"SOCKET-BINDUNIX-ERROR",
"UNIX sockets are not available under Windows");
1621 if (openUNIX(socktype, protocol)) {
1622 xsink->
raiseErrnoException(
"SOCKET-BIND-ERROR", errno,
"error opening UNIX socket ('%s') for bind", name);
1626 hashdecl sockaddr_un addr;
1627 addr.sun_family = AF_UNIX;
1629 strncpy(addr.sun_path, name,
sizeof(addr.sun_path) - 1);
1630 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1632 if (bindIntern((sockaddr*)&addr,
sizeof(
struct sockaddr_un), -1,
false, xsink))
1636 socketname = addr.sun_path;
1643 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) {
1645 family = q_get_af(family);
1646 socktype = q_get_sock_type(socktype);
1651 do_resolve_event(name, service);
1652 if (ai.
getInfo(xsink, name, service, family, AI_PASSIVE, socktype, protocol))
1658 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1659 do_resolved_event(p->ai_addr);
1662 if (openINET(aip->ai_family, aip->ai_socktype, protocol)) {
1663 qore_socket_error(xsink,
"SOCKET-BINDINET-ERROR",
"error opening socket for bind", 0, name, service);
1667 int prt = q_get_port_from_addr(aip->ai_addr);
1671 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1672 if (!bindIntern(p->ai_addr, p->ai_addrlen, prt, reuseaddr)) {
1677 en = sock_get_raw_error();
1682 qore_socket_error_intern(en, xsink,
"SOCKET-BIND-ERROR",
"error binding on socket", 0, name, service);
1689 if (sock == QORE_INVALID_SOCKET) {
1690 se_not_open(
"Socket",
"getPeerInfo", xsink);
1694 hashdecl sockaddr_storage addr;
1695 socklen_t len =
sizeof addr;
1696 if (getpeername(sock, (
struct sockaddr*)&addr, &len)) {
1697 qore_socket_error(xsink,
"SOCKET-GETPEERINFO-ERROR",
"error in getpeername()");
1701 return getAddrInfo(addr, len, host_lookup);
1707 if (sock == QORE_INVALID_SOCKET) {
1708 se_not_open(
"Socket",
"getSocketInfo", xsink);
1712 hashdecl sockaddr_storage addr;
1713#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1715 int len =
sizeof addr;
1717 socklen_t len =
sizeof addr;
1720 if (getsockname(sock, (
struct sockaddr*)&addr, &len)) {
1721 qore_socket_error(xsink,
"SOCKET-GETSOCKETINFO-ERROR",
"error in getsockname()");
1725 return getAddrInfo(addr, len, host_lookup);
1728 DLLLOCAL
QoreHashNode* getAddrInfo(
const struct sockaddr_storage& addr, socklen_t len,
bool host_lookup =
true)
const {
1731 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1733 char host[NI_MAXHOST + 1];
1735 if (!getnameinfo((
struct sockaddr*)&addr, qore_get_in_len((
struct sockaddr*)&addr), host,
sizeof(host), 0, 0, 0)) {
1743 char ifname[INET6_ADDRSTRLEN];
1744 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr*)&addr), ifname,
sizeof(ifname))) {
1751 if (addr.ss_family == AF_INET) {
1752 hashdecl sockaddr_in* s = (
hashdecl sockaddr_in*)&addr;
1753 tport = ntohs(s->sin_port);
1755 hashdecl sockaddr_in6* s = (
hashdecl sockaddr_in6*)&addr;
1756 tport = ntohs(s->sin6_port);
1762 else if (addr.ss_family == AF_UNIX) {
1763 assert(!socketname.empty());
1779 hashdecl sockaddr_storage addr;
1781 socklen_t len =
sizeof addr;
1782 if (getpeername(sock, (
struct sockaddr*)&addr, &len))
1785 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1787 char ifname[INET6_ADDRSTRLEN];
1788 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr *)&addr), ifname,
sizeof(ifname))) {
1793 char host[NI_MAXHOST + 1];
1794 if (!getnameinfo((
struct sockaddr *)&addr, qore_get_in_len((
struct sockaddr *)&addr), host,
sizeof(host),
1800 else if (addr.ss_family == AF_UNIX) {
1802 hashdecl sockaddr_un *addr_un = (
hashdecl sockaddr_un *)&addr;
1803 astr->
sprintf(
"UNIX socket: %s", addr_un->sun_path);
1816 DLLLOCAL
int readByteFromBuffer(
char& output) {
1818 assert(sock != QORE_INVALID_SOCKET);
1825 output = *(rbuf + bufoffset);
1838 int timeout,
bool do_event =
true) {
1841 assert(sock != QORE_INVALID_SOCKET);
1846 buf = rbuf + bufoffset;
1865 if (timeout != -1 && !isDataAvailable(timeout, meth, xsink)) {
1869 se_timeout(
"Socket", meth, timeout, xsink);
1877 rc = ::recv(sock, rbuf, DEFAULT_SOCKET_BUFSIZE, flags);
1878 if (rc == QORE_SOCKET_ERROR) {
1883 if (errno == ECONNRESET) {
1884 se_closed(
"Socket", meth, xsink);
1888 qore_socket_error(xsink,
"SOCKET-RECV-ERROR",
"error in recv()", meth);
1898 rc = ssl->read(meth, rbuf, DEFAULT_SOCKET_BUFSIZE, timeout, xsink);
1914 do_read_event(rc, rc);
1928 bool exit_early =
false) {
1931 if (sock == QORE_INVALID_SOCKET) {
1932 se_not_open(
"Socket", meth, xsink,
"readHTTPData");
1937 PrivateQoreSocketThroughputHelper th(
this,
false);
1952 rc = brecv(xsink, meth, buf, 1, 0, timeout,
false);
1960 se_closed(
"Socket", meth, xsink);
1962 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");
1968 if (++count == QORE_MAX_HEADER_SIZE) {
1969 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"header size cannot exceed " QSD
" bytes", count);
1980 if (exit_early && hdr->
empty())
1987 }
else if (c ==
'\r') {
2002 case 0: hdr->concat(
'\r');
break;
2003 case 1: hdr->concat(
"\r\n");
break;
2004 case 2: hdr->concat(
"\r\n\r");
break;
2005 case 3: hdr->concat(
'\n');
break;
2015 th.finalize(hdr->
size());
2017 return hdr.release();
2021 int source = QORE_SOURCE_SOCKET) {
2023 if (sock == QORE_INVALID_SOCKET) {
2024 se_not_open(
"Socket",
"recv", xsink,
"recv");
2030 se_in_op(
"Socket",
"recv", xsink);
2033 se_in_op_thread(
"Socket",
"recv", xsink);
2037 PrivateQoreSocketThroughputHelper th(
this,
false);
2039 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2046 rc = brecv(xsink,
"recv", buf, bs, 0, timeout,
false);
2052 printd(5,
"qore_socket_private::recv(" QSD
", %d) bs=" QSD
", br=" QSD
", rc=" QSD
", errno: %d "
2053 "(%s)\n", bufsize, timeout, bs, str->
size(), rc, errno, strerror(errno));
2061 do_read_event(rc, str->
size(), bufsize, source);
2065 if (str->
size() >= (
size_t)bufsize)
2067 if ((bufsize - str->
size()) < bs)
2068 bs = bufsize - str->
size();
2072 printd(5,
"qore_socket_private::recv() received " QSD
" byte(s), bufsize=" QSD
", strlen=" QSD
" str='%s'\n",
2079 th.finalize(str->
size());
2086 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2088 return str.release();
2092 int source = QORE_SOURCE_SOCKET) {
2094 if (sock == QORE_INVALID_SOCKET) {
2095 se_not_open(
"Socket",
"recv", xsink,
"recvAll");
2101 se_in_op(
"Socket",
"recv", xsink);
2104 se_in_op_thread(
"Socket",
"recv", xsink);
2108 PrivateQoreSocketThroughputHelper th(
this,
false);
2114 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2121 do_read_event(rc, rc);
2124 if (isDataAvailable(0,
"recv", xsink)) {
2126 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
2132 th.finalize(str->
size());
2138 do_read_event(rc, str->
size());
2139 }
while (isDataAvailable(0,
"recv", xsink));
2142 th.finalize(str->
size());
2150 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2152 return str.release();
2159 if (sock == QORE_INVALID_SOCKET) {
2160 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinary");
2166 se_in_op(
"Socket",
"recvBinary", xsink);
2169 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2173 PrivateQoreSocketThroughputHelper th(
this,
false);
2175 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2181 rc = brecv(xsink,
"recvBinary", buf, bs, 0, timeout);
2188 if (b->
size() >= (
size_t)bufsize)
2190 if ((bufsize - b->
size()) < bs)
2191 bs = bufsize - b->
size();
2195 th.finalize(b->
size());
2205 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2207 printd(5,
"qore_socket_private::recvBinary() received " QSD
" byte(s), bufsize=" QSD
", blen=" QSD
"\n", b->
size(), bufsize, b->
size());
2213 if (sock == QORE_INVALID_SOCKET) {
2214 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinaryAll");
2220 se_in_op(
"Socket",
"recvBinary", xsink);
2223 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2227 PrivateQoreSocketThroughputHelper th(
this,
false);
2234 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2241 do_read_event(rc, rc);
2244 if (isDataAvailable(0,
"recvBinary", xsink)) {
2246 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false);
2251 th.finalize(b->
size());
2258 do_read_event(rc, b->
size());
2259 }
while (isDataAvailable(0,
"recvBinary", xsink));
2262 th.finalize(b->
size());
2268 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2276 if (sock == QORE_INVALID_SOCKET) {
2277 se_not_open(
"Socket",
"recvToOutputStream", xsink);
2282 se_in_op(
"Socket",
"recvToOutputStream", xsink);
2285 se_in_op_thread(
"Socket",
"recvToOutputStream", xsink);
2289 qore_socket_op_helper oh(
this);
2293 while (size < 0 || br < size) {
2295 int bn = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - br, DEFAULT_SOCKET_BUFSIZE);
2297 qore_offset_t rc = brecv(xsink,
"recvToOutputStream", buf, bn, 0, timeout);
2306 xsink->
raiseException(
"SOCKET-RECV-ERROR",
"Unexpected end of stream");
2312 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, buf, rc);
2318 os->
write(buf, rc, xsink);
2337 do_data_event(QORE_EVENT_HTTP_HEADERS_READ, source, **hdr);
2338 return hdr.release();
2342 qore_offset_t& rc,
int source,
const char* headers_raw_key =
"headers-raw") {
2351 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"remote closed the connection while reading the HTTP header");
2356 return processHttpHeaderString(xsink, hdr, info, source, headers_raw_key);
2361 QoreHashNode* info,
int source,
const char* headers_raw_key =
"headers-raw") {
2362 const char* buf = hdr->
c_str();
2364 if ((p = (
char*)strstr(buf,
"\r\n"))) {
2367 }
else if ((p = (
char*)strchr(buf,
'\n'))) {
2370 }
else if ((p = (
char*)strchr(buf,
'\r'))) {
2376 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"invalid header received with embedded nulls in "
2377 "Socket::readHTTPHeader()");
2382 if (!(t1 = (
char*)strstr(buf,
"HTTP/"))) {
2383 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"missing HTTP version string in "
2384 "first header line in Socket::readHTTPHeader()");
2391 int flags = CHF_PROCESS;
2398 flags |= CHF_HTTP11;
2404 const char* info_key;
2406 char* t2 = (
char*)strchr(buf + 8,
' ');
2409 if (isdigit(*(t2))) {
2411 if (strlen(t2) > 4) {
2418 info_key =
"response-uri";
2420 char* t2 = (
char*)strchr(buf,
' ');
2425 t1 = strchr(t2,
' ');
2433 info_key =
"request-uri";
2434 flags |= CHF_REQUEST;
2438 if (info || (event_queue && event_data)) {
2440 if (info && event_queue && event_data) {
2443 if (event_queue && event_data) {
2444 do_data_event_intern(QORE_EVENT_SOCKET_DATA_READ, source, **status_line);
2447 info->
setKeyValue(info_key, *status_line,
nullptr);
2449 status_line.release();
2452 bool close = convertHeaderToHash(*h, p, flags, info, &http_exp_chunked_body, headers_raw_key);
2453 do_read_http_header(QORE_EVENT_HTTP_MESSAGE_RECEIVED, *h, source);
2456 if ((flags & CHF_REQUEST) && info) {
2464 DLLLOCAL
int runHeaderCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2466 bool send_aborted =
false,
QoreObject* obj =
nullptr) {
2475 arg->
setKeyValue(
"send_aborted", send_aborted, xsink);
2476 args->push(arg,
nullptr);
2479 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2482 DLLLOCAL
int runTrailerCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2485 if (runCallback(xsink, cname, mname, rv, callback, l,
nullptr))
2488 switch (rv->getType()) {
2496 xsink->
raiseException(
"HTTP-TRAILER-ERROR",
"chunked callback returned type '%s'; expecting 'hash' "
2497 "or 'NOTHING'", rv->getTypeName());
2503 DLLLOCAL
int runDataCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2510 args->push(arg,
nullptr);
2513 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2529 return *xsink ? -1 : 0;
2532 DLLLOCAL
int sendHttpChunkedWithCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2534 bool* aborted =
nullptr) {
2536 assert(!aborted || !(*aborted));
2538 if (sock == QORE_INVALID_SOCKET) {
2539 se_not_open(cname, mname, xsink,
"sendHttpChunkedWithCallback");
2540 return QSE_NOT_OPEN;
2544 se_in_op(cname, mname, xsink);
2547 se_in_op_thread(cname, mname, xsink);
2551 PrivateQoreSocketThroughputHelper th(
this,
true);
2554 bool nb = (timeout_ms >= 0);
2556 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2560 qore_socket_op_helper oh(
this);
2569 bool data_available = tryReadSocketData(mname, xsink);
2571 if (data_available || *xsink) {
2573 return *xsink ? -1 : 0;
2579 rc = runCallback(xsink, cname, mname, res, send_callback, &l);
2588 const char* data_ptr =
nullptr;
2589 size_t data_size = 0;
2591 switch (res->getType()) {
2599 data_ptr = str->
c_str();
2600 data_size = str->
size();
2612 data_ptr =
static_cast<const char*
>(b->
getPtr());
2613 data_size = b->
size();
2625 const char* key = hi.getKey();
2632 do_header(key, buf, li.getValue());
2634 do_header(key, buf, v);
2645 xsink->
raiseException(
"SOCKET-CALLBACK-ERROR",
"HTTP chunked data callback returned type '%s'; expecting one of: 'string', 'binary', 'hash', 'nothing' (or 'NULL')", res->getTypeName());
2651 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2657 if (data_ptr && data_size) {
2658 rc = sendIntern(xsink, cname, mname, data_ptr, data_size, timeout_ms, total,
true);
2663 if (buf.
empty() && (!data_ptr || !data_size)) {
2664 buf.
set(
"0\r\n\r\n");
2668 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2674 switch (res->getType()) {
2677 if (!str->
empty()) {
2678 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *str);
2686 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *b);
2693 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, source, *h);
2701 if (aborted && *xsink) {
2702 bool data_available = tryReadSocketData(mname, xsink);
2704 if (data_available) {
2706 return *xsink ? -1 : 0;
2715 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2721 return rc < 0 || sock == QORE_INVALID_SOCKET ? -1 : 0;
2724 DLLLOCAL
int sendIntern(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2725 int timeout_ms,
int64& total,
bool stream =
false) {
2731 bool nb = (timeout_ms >= 0);
2736 rc = ssl->write(mname, buf + bs, size - bs, timeout_ms, xsink);
2739 rc = ::send(sock, buf + bs, size - bs, 0);
2746 if (nb && (errno == EAGAIN
2748 || errno == EWOULDBLOCK
2751 if (!isWriteFinished(timeout_ms, mname, xsink)) {
2754 se_timeout(
"Socket", mname, timeout_ms, xsink);
2760 if (errno != EINTR) {
2762 xsink->
raiseErrnoException(
"SOCKET-SEND-ERROR", errno,
"error while executing %s::%s()", cname, mname);
2766 if (!stream && errno == EPIPE)
2770 if (!stream && errno == ECONNRESET)
2781 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2786 do_send_event(rc, bs, size);
2797 DLLLOCAL
int send(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2798 int timeout_ms = -1,
int source = QORE_SOURCE_SOCKET) {
2800 if (sock == QORE_INVALID_SOCKET) {
2801 se_not_open(cname, mname, xsink,
"send");
2802 return QSE_NOT_OPEN;
2806 se_in_op(cname, mname, xsink);
2809 se_in_op_thread(cname, mname, xsink);
2816 PrivateQoreSocketThroughputHelper th(
this,
true);
2819 bool nb = (timeout_ms >= 0);
2821 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2827 qore_offset_t rc = sendIntern(xsink, cname, mname, buf, size, timeout_ms, total);
2830 if (rc > 0 && source > 0) {
2831 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, buf, size);
2834 return rc < 0 || sock == QORE_INVALID_SOCKET ? rc : 0;
2839 if (sock == QORE_INVALID_SOCKET) {
2840 se_not_open(
"Socket",
"sendFromInputStream", xsink);
2845 se_in_op(
"Socket",
"sendFromInputStream", xsink);
2848 se_in_op_thread(
"Socket",
"sendFromInputStream", xsink);
2852 qore_socket_op_helper oh(
this);
2854 PrivateQoreSocketThroughputHelper th(
this,
true);
2857 bool nb = (timeout >= 0);
2859 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2863 char buf[DEFAULT_SOCKET_BUFSIZE];
2866 while (size < 0 || sent < size) {
2867 int64 toRead = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - sent, DEFAULT_SOCKET_BUFSIZE);
2871 r = is->
read(buf, toRead, xsink);
2880 xsink->
raiseException(
"SOCKET-SEND-ERROR",
"Unexpected end of stream");
2886 qore_offset_t rc = sendIntern(xsink,
"Socket",
"sendFromInputStream", buf, r, timeout, total);
2890 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, QORE_SOURCE_SOCKET, buf, r);
2897 if (sock == QORE_INVALID_SOCKET) {
2898 se_not_open(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2903 se_in_op(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2906 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2910 qore_socket_op_helper oh(
this);
2912 PrivateQoreSocketThroughputHelper th(
this,
true);
2915 bool nb = (timeout >= 0);
2917 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2923 buf->preallocate(max_chunk_size);
2929 r = is->
read((
void*)buf->getPtr(),
sizeof(max_chunk_size), xsink);
2936 str.
sprintf(
"%x\r\n", (
int)r);
2937 int rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2941 bool trailers =
false;
2945 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", (
const char*)buf->getPtr(), r, timeout, total,
true);
2948 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, QORE_SOURCE_SOCKET, buf->getPtr(), r);
2949 }
else if (trailer_callback) {
2953 if (runTrailerCallback(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", *trailer_callback, l, h))
2957 do_headers(str, *h, 0,
false);
2959 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2963 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, **h);
2971 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
2985 if (sock == QORE_INVALID_SOCKET) {
2986 se_not_open(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2991 se_in_op(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
2994 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3004 const char* key = hi.getKey();
3009 do_header(key, buf, li.getValue());
3012 do_header(key, buf, v);
3017 sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyTrailer", buf.
getBuffer(), buf.
size(), timeout, total,
true);
3019 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, *headers);
3023 DLLLOCAL
void getSendHttpMessageHeaders(
QoreString& hdr,
QoreHashNode* info,
const char* method,
const char* path,
3024 const char* http_version,
const QoreHashNode* headers,
size_t size,
int source) {
3026 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3033 getSendHttpMessageHeadersCommon(hdr, info, headers, size, source);
3037 size_t size,
int source) {
3039 do_send_http_message_event(hdr, headers, source);
3044 do_headers(hdr, headers, size);
3048 const char* method,
const char* path,
const char* http_version,
const QoreHashNode* headers,
3056 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3063 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3064 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3076 hdr.
sprintf(
"HTTP/%s %03d %s", http_version, code, desc);
3084 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3085 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3094 assert(!(data && send_callback));
3095 assert(!(data && input_stream));
3096 assert(!(send_callback && input_stream));
3099 do_send_http_message_event(hdr, headers, source);
3104 do_headers(hdr, headers, size && data ? size : 0);
3110 if ((rc = send(xsink, cname, mname, hdr.
c_str(), hdr.
size(), timeout_ms, -1)))
3115 int rc = send(xsink, cname, mname, (
char*)data, size, timeout_ms, -1);
3118 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, *body);
3120 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, data, size);
3124 }
else if (send_callback) {
3126 assert(!aborted || !(*aborted));
3127 return sendHttpChunkedWithCallback(xsink, cname, mname, *send_callback, *l, source, timeout_ms, aborted);
3128 }
else if (input_stream) {
3130 sendHttpChunkedBodyFromInputStream(input_stream, max_chunk_size, timeout_ms, xsink, l, trailer_callback);
3131 return *xsink ? -1 : 0;
3140 if (sock == QORE_INVALID_SOCKET) {
3141 se_not_open(cname,
"readHTTPChunkedBodyBinary", xsink);
3146 se_in_op(cname,
"readHTTPChunkedBodyBinary", xsink);
3149 se_in_op_thread(cname,
"readHTTPChunkedBodyBinary", xsink);
3154 if (http_exp_chunked_body)
3155 http_exp_chunked_body =
false;
3157 qore_socket_op_helper oh(
this);
3170 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 1, 0, timeout,
false);
3174 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3181 if (!state && c ==
'\r')
3183 else if (state && c ==
'\n')
3197 char* p = (
char*)strchr(str.
getBuffer(),
';');
3200 long size = strtol(str.
c_str(), 0, 16);
3201 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
size(), source);
3207 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3214 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3218 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, bs, 0, timeout,
false);
3223 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3228 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, buf, (
size_t)rc);
3232 os->
write(buf, rc, xsink);
3254 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 2 - br, 0, timeout,
false);
3258 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3265 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3267 if (recv_callback && !os) {
3268 if (runDataCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, *b,
true))
3284 if (!recv_callback && !os) {
3292 return recv_callback ? 0 : h.release();
3294 if (recv_callback) {
3297 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3298 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3301 if (recv_callback) {
3302 runHeaderCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, h->
empty() ?
nullptr : *h,
3303 info.release(),
false, obj);
3314 if (sock == QORE_INVALID_SOCKET) {
3315 se_not_open(cname,
"readHTTPChunkedBody", xsink);
3320 se_in_op(cname,
"readHTTPChunkedBody", xsink);
3323 se_in_op_thread(cname,
"readHTTPChunkedBody", xsink);
3328 if (http_exp_chunked_body)
3329 http_exp_chunked_body =
false;
3331 qore_socket_op_helper oh(
this);
3344 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 1, 0, timeout,
false);
3348 se_closed(cname,
"readHTTPChunkedBody", xsink);
3355 if (!state && c ==
'\r')
3357 else if (state && c ==
'\n')
3371 char* p = (
char*)strchr(str.
getBuffer(),
';');
3375 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
strlen(), source);
3381 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3391 qore_offset_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3396 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, bs, 0, timeout,
false);
3400 se_closed(cname,
"readHTTPChunkedBody", xsink);
3406 buf->concat(tbuf, rc);
3408 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, tbuf, (
size_t)rc);
3424 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 2 - br, 0, timeout,
false);
3428 se_closed(cname,
"readHTTPChunkedBody", xsink);
3435 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3437 if (recv_callback) {
3438 if (runDataCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, *buf,
true))
3451 if (!recv_callback) {
3459 return recv_callback ? 0 : h.release();
3461 if (recv_callback) {
3464 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3465 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3468 if (recv_callback) {
3469 runHeaderCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, h->
empty() ?
nullptr : *h,
3470 info.release(),
false, obj);
3477 DLLLOCAL
static void do_accept_encoding(
char* t,
QoreHashNode& info) {
3486 while (*a && *a !=
';' && *a !=
',')
3490 l->push(str.release(),
nullptr);
3500 info.
setKeyValue(
"accept-encoding", l.release(), 0);
3503 DLLLOCAL
bool do_accept_charset(
char* t,
QoreHashNode& info) {
3504 bool acceptcharset =
false;
3519 if (*a ==
'u' || *a ==
'U') {
3521 if (*a ==
't' || *a ==
'T') {
3523 if (*a ==
'f' || *a ==
'F') {
3535 }
else if (*a ==
',') {
3539 }
else if (*a ==
';') {
3548 acceptcharset =
true;
3552 ac->concat(t, div - t);
3557 info.
setKeyValue(
"accept-charset", ac.release(), 0);
3558 acceptcharset =
true;
3562 return acceptcharset;
3567 bool* chunked =
nullptr,
const char* headers_raw_key =
"headers-raw") {
3568 bool close = !(flags & CHF_HTTP11);
3570 const char* senc =
nullptr;
3572 bool acceptcharset =
false;
3580 std::string raw_key;
3585 if ((p = strstr(buf,
"\r\n"))) {
3588 }
else if ((p = strchr(buf,
'\n'))) {
3591 }
else if ((p = strchr(buf,
'\r'))) {
3596 char* t = strchr(buf,
':');
3601 while (t && qore_isblank(*t))
3611 if (flags & CHF_PROCESS) {
3612 if (!strcmp(buf,
"connection")) {
3613 if (flags & CHF_HTTP11) {
3614 if (strcasestr(t,
"close"))
3617 if (strcasestr(t,
"keep-alive"))
3620 }
else if (!strcmp(buf,
"content-type")) {
3621 char* a = strcasestr(t,
"charset=");
3624 char* e = strchr(a + 8,
';');
3628 cs.
concat(a + 8, e - a - 8);
3637 size_t len = cs.
size();
3647 }
while (a > t && (*a ==
' ' || *a ==
';'));
3654 ct->concat(t, a - t + 1);
3660 info->
setKeyValue(
"body-content-type", ct.release(),
nullptr);
3666 info->
setKeyValue(
"body-content-type", val->refSelf(),
nullptr);
3669 }
else if (chunked && !strcmp(buf,
"transfer-encoding") && !strcasecmp(t,
"chunked")) {
3672 if (!strcmp(buf,
"accept-charset"))
3673 acceptcharset = do_accept_charset(t, *info);
3674 else if ((flags & CHF_REQUEST) && !strcmp(buf,
"accept-encoding"))
3675 do_accept_encoding(t, *info);
3680 if (raw_hdr && val) {
3681 val_copy = val->realCopy();
3685 hash_assignment_priv ha(*h, buf);
3686 if (!(*ha).isNothing()) {
3688 if ((*ha).getType() ==
NT_LIST) {
3692 l->
push(ha.swap(l),
nullptr);
3694 l->
push(val.release(),
nullptr);
3696 ha.assign(val.release(), 0);
3700 hash_assignment_priv ha(*raw_hdr, raw_key);
3701 if (!(*ha).isNothing()) {
3703 if ((*ha).getType() ==
NT_LIST) {
3707 l->
push(ha.swap(l),
nullptr);
3709 l->
push(val_copy.release(),
nullptr);
3711 ha.assign(val_copy.release(),
nullptr);
3715 if ((flags & CHF_PROCESS)) {
3719 if (info && !acceptcharset)
3726 DLLLOCAL
int recvix(
const char* meth,
int len,
void* targ,
int timeout_ms,
ExceptionSink* xsink) {
3728 if (sock == QORE_INVALID_SOCKET) {
3729 se_not_open(
"Socket", meth, xsink,
"recvix");
3730 return QSE_NOT_OPEN;
3734 se_in_op(
"Socket", meth, xsink);
3737 se_in_op_thread(
"Socket", meth, xsink);
3741 PrivateQoreSocketThroughputHelper th(
this,
false);
3746 qore_offset_t rc = brecv(xsink, meth, buf, len - br, 0, timeout_ms);
3748 do_read_error(rc, meth, timeout_ms, xsink);
3752 memcpy(targ, buf, rc);
3760 do_data_event(QORE_EVENT_SOCKET_DATA_READ, QORE_SOURCE_SOCKET, targ, br);
3766 if (warn_callback_arg) {
3767 warn_callback_arg.
discard(xsink);
3770 warn_queue->deref(xsink);
3771 warn_queue =
nullptr;
3773 tp_warning_bs = 0.0;
3779 int64 min_ms = 1000) {
3782 if (warning_ms <= 0 && warning_bs <= 0) {
3783 xsink->
raiseException(
"SOCKET-SETWARNINGQUEUE-ERROR",
"Socket::setWarningQueue() at least one of warning "
3784 "ms argument: " QLLD
" and warning B/s argument: " QLLD
" must be greater than zero; to clear, call "\
3785 "Socket::clearWarningQueue() with no arguments", warning_ms, warning_bs);
3795 warn_queue->
deref(xsink);
3796 warn_callback_arg.
discard(xsink);
3799 warn_queue = qholder.release();
3800 warn_callback_arg = holder.release();
3801 tl_warning_us = (
int64)warning_ms * 1000;
3802 tp_warning_bs = warning_bs;
3803 tp_us_min = min_ms * 1000;
3806 DLLLOCAL
void getUsageInfo(
QoreHashNode& h, qore_socket_private& s)
const {
3814 h.
setKeyValue(
"bytes_sent", tp_bytes_sent + s.tp_bytes_sent, 0);
3815 h.
setKeyValue(
"bytes_recv", tp_bytes_recv + s.tp_bytes_sent, 0);
3816 h.
setKeyValue(
"us_sent", tp_us_sent + s.tp_us_sent, 0);
3817 h.
setKeyValue(
"us_recv", tp_us_recv + s.tp_us_recv, 0);
3840 DLLLOCAL
void clearStats() {
3847 DLLLOCAL
void doTimeoutWarning(
const char* op,
int64 dt) {
3849 assert(dt > tl_warning_us);
3857 if (warn_callback_arg)
3860 warn_queue->pushAndTakeRef(h);
3863 DLLLOCAL
void doThroughputWarning(
bool send,
int64 bytes,
int64 dt,
double bs) {
3865 assert(bs < tp_warning_bs);
3875 if (warn_callback_arg)
3878 warn_queue->pushAndTakeRef(h);
3881 DLLLOCAL
bool pendingHttpChunkedBody()
const {
3882 return http_exp_chunked_body && sock != QORE_INVALID_SOCKET;
3885 DLLLOCAL
void setSslVerifyMode(
int mode) {
3887 ssl_verify_mode = mode;
3889 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3892 DLLLOCAL
void acceptAllCertificates(
bool accept_all =
true) {
3893 ssl_accept_all_certs = accept_all;
3895 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
3900 ssl_err_str->
concat(
"; ");
3901 ssl_err_str->
concat(err_str);
3904 ssl_err_str = err_str;
3909 sock.priv->getUsageInfo(h, *s.priv);
3912 DLLLOCAL
static qore_socket_private* get(
QoreSocket& sock) {
3916 DLLLOCAL
static const qore_socket_private* get(
const QoreSocket& sock) {
3920 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:271
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:590
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:50
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: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
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: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 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:74
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
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:276
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