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);
102#define GETSOCKOPT_ARG_4 char*
103#define SETSOCKOPT_ARG_4 const char*
104#define SHUTDOWN_ARG SD_BOTH
105#define QORE_INVALID_SOCKET ((int)INVALID_SOCKET)
106#define QORE_SOCKET_ERROR SOCKET_ERROR
107DLLLOCAL
int check_windows_rc(
int rc);
108DLLLOCAL
int windows_set_errno();
111#define ECONNRESET WSAECONNRESET
116#define GETSOCKOPT_ARG_4 void*
117#define SETSOCKOPT_ARG_4 void*
118#define SHUTDOWN_ARG SHUT_RDWR
119#define QORE_INVALID_SOCKET -1
120#define QORE_SOCKET_ERROR -1
124class PrivateDataListHolder {
126 DLLLOCAL PrivateDataListHolder(
ExceptionSink* xsink) : xsink(xsink) {
129 DLLLOCAL ~PrivateDataListHolder() {
130 for (
auto& i : pd_vec)
138 pd_vec.push_back(pd);
143 typedef std::vector<T*> pd_vec_t;
148hashdecl qore_socketsource_private {
152 DLLLOCAL qore_socketsource_private() : address(0), hostname(0) {
155 DLLLOCAL ~qore_socketsource_private() {
156 if (address) address->deref();
157 if (hostname) hostname->deref();
165 DLLLOCAL
void setAddress(
const char* addr) {
170 DLLLOCAL
void setHostName(
const char* host) {
177 o->
setValue(
"source", address, xsink);
182 o->
setValue(
"source_host", hostname, xsink);
188class OptionalNonBlockingHelper {
190 qore_socket_private& sock;
194 DLLLOCAL OptionalNonBlockingHelper(qore_socket_private& s,
bool n_set,
ExceptionSink* xs);
195 DLLLOCAL ~OptionalNonBlockingHelper();
198class PrivateQoreSocketTimeoutBase {
200 DLLLOCAL PrivateQoreSocketTimeoutBase(qore_socket_private* s) : sock(s), start(sock ? q_clock_getmicros() : 0) {
204 hashdecl qore_socket_private* sock;
208class PrivateQoreSocketTimeoutHelper :
public PrivateQoreSocketTimeoutBase {
210 DLLLOCAL PrivateQoreSocketTimeoutHelper(qore_socket_private* s,
const char* op);
211 DLLLOCAL ~PrivateQoreSocketTimeoutHelper();
217class PrivateQoreSocketThroughputHelper :
public PrivateQoreSocketTimeoutBase {
219 DLLLOCAL PrivateQoreSocketThroughputHelper(qore_socket_private* s,
bool snd);
220 DLLLOCAL ~PrivateQoreSocketThroughputHelper();
222 DLLLOCAL
void finalize(
int64 bytes);
228hashdecl qore_socket_private;
230hashdecl qore_socket_op_helper {
232 qore_socket_private* s;
235 DLLLOCAL qore_socket_op_helper(qore_socket_private* sock);
236 DLLLOCAL ~qore_socket_op_helper();
239class SSLSocketHelperHelper {
241 qore_socket_private* s;
242 SSLSocketHelper* ssl;
243 bool context_saved =
false;
246 DLLLOCAL SSLSocketHelperHelper(qore_socket_private* sock,
bool set_thread_context =
false);
248 DLLLOCAL ~SSLSocketHelperHelper();
250 DLLLOCAL
void error();
253constexpr int SCIPS_CONNECT = 0;
254constexpr int SCIPS_CHECK_CONNECT = 1;
256class SocketConnectInetPollState :
public AbstractPollState {
258 DLLLOCAL SocketConnectInetPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* host,
259 const char* service,
int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0);
271 qore_socket_private* sock;
272 std::string host, service;
273 hashdecl addrinfo* p =
nullptr;
275 int state = SCIPS_CONNECT;
290class SocketConnectUnixPollState :
public AbstractPollState {
292 DLLLOCAL SocketConnectUnixPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* name,
293 int type = SOCK_STREAM,
int protocol = 0);
304 qore_socket_private* sock;
306 hashdecl sockaddr_un addr;
307 int state = SCIPS_CONNECT;
316class SocketConnectSslPollState :
public AbstractPollState {
318 DLLLOCAL SocketConnectSslPollState(
ExceptionSink* xsink, qore_socket_private* sock,
330 qore_socket_private* sock;
336class SocketAcceptPollState :
public AbstractPollState {
338 DLLLOCAL SocketAcceptPollState(
ExceptionSink* xsink, qore_socket_private* sock);
349 DLLLOCAL
int getDescriptor()
const {
354 qore_socket_private* sock;
358class SocketAcceptSslPollState :
public AbstractPollState {
360 DLLLOCAL SocketAcceptSslPollState(
ExceptionSink* xsink, qore_socket_private* sock,
372 qore_socket_private* sock;
375class SocketSendPollState :
public AbstractPollState {
377 DLLLOCAL SocketSendPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* data,
size_t size);
388 DLLLOCAL
size_t getBytesSent()
const {
393 qore_socket_private* sock;
399class SocketRecvPollState :
public AbstractPollState {
401 DLLLOCAL SocketRecvPollState(
ExceptionSink* xsink, qore_socket_private* sock,
size_t size);
412 DLLLOCAL
virtual QoreValue takeOutput() {
419 DLLLOCAL
size_t getBytesReceived()
const {
424 qore_socket_private* sock;
430class SocketRecvPacketPollState :
public AbstractPollState {
432 DLLLOCAL SocketRecvPacketPollState(
ExceptionSink* xsink, qore_socket_private* sock);
443 DLLLOCAL
virtual QoreValue takeOutput() {
450 DLLLOCAL
size_t getBytesReceived()
const {
451 return bin ? bin->size() : 0;
455 qore_socket_private* sock;
460class SocketRecvUntilBytesPollState :
public AbstractPollState {
462 DLLLOCAL SocketRecvUntilBytesPollState(
ExceptionSink* xsink, qore_socket_private* sock,
const char* bytes,
474 DLLLOCAL
virtual QoreValue takeOutput() {
475 size_t len = bin->size();
482 DLLLOCAL
size_t getBytesReceived()
const {
483 return bin ? bin->size() : 0;
487 qore_socket_private* sock;
498hashdecl qore_socket_private {
499 friend class PrivateQoreSocketTimeoutHelper;
500 friend class PrivateQoreSocketThroughputHelper;
501 friend class SocketConnectInetPollState;
504 static thread_local qore_socket_private* current_socket;
506 int sock, sfamily, port, stype, sprot;
509 int64 connection_id = 0;
513 std::string socketname;
515 std::string client_target;
516 SSLSocketHelper* ssl =
nullptr;
517 Queue* event_queue =
nullptr,
518 * warn_queue =
nullptr;
521 std::string assume_http_encoding =
"ISO-8859-1";
524 char rbuf[DEFAULT_SOCKET_BUFSIZE];
530 int64 tl_warning_us = 0;
531 double tp_warning_bs = 0;
532 int64 tp_bytes_sent = 0,
544 http_exp_chunked_body =
false,
545 ssl_accept_all_certs =
false,
546 ssl_capture_remote_cert =
false,
550 ssl_verify_mode = SSL_VERIFY_NONE;
558 DLLLOCAL qore_socket_private(
int n_sock = QORE_INVALID_SOCKET,
int n_sfamily = AF_UNSPEC,
560 sock(n_sock), sfamily(n_sfamily), port(-1), stype(n_stype), sprot(n_prot), enc(n_enc) {
563 DLLLOCAL ~qore_socket_private() {
567 assert(!event_queue);
571 DLLLOCAL
bool isOpen() {
572 return sock != QORE_INVALID_SOCKET;
575 DLLLOCAL
int close() {
576 return close_internal();
579 DLLLOCAL
int close_and_reset() {
580 assert(sock != QORE_INVALID_SOCKET);
584 rc = ::closesocket(sock);
589 if (!rc || sock_get_error() != EINTR)
593 sock = QORE_INVALID_SOCKET;
609 if (http_exp_chunked_body) {
610 http_exp_chunked_body =
false;
619 client_target.clear();
623 DLLLOCAL
int close_internal() {
626 ssl_err_str->deref();
627 ssl_err_str =
nullptr;
630 remote_cert->
deref(
nullptr);
631 remote_cert =
nullptr;
641 if (!socketname.empty()) {
643 unlink(socketname.c_str());
651 return close_and_reset();
657 DLLLOCAL
void setAssumedEncoding(
const char* str) {
658 assume_http_encoding = str;
661 DLLLOCAL
const char* getAssumedEncoding()
const {
662 return assume_http_encoding.c_str();
665 DLLLOCAL
int getSendTimeout()
const {
668#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
671 int size =
sizeof(
hashdecl timeval);
673 socklen_t size =
sizeof(
hashdecl timeval);
676 if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
679 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
682 DLLLOCAL
int getRecvTimeout()
const {
685#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
688 int size =
sizeof(
hashdecl timeval);
690 socklen_t size =
sizeof(
hashdecl timeval);
693 if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
696 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
699 DLLLOCAL
int getPort() {
701 if (sock == QORE_INVALID_SOCKET || (sfamily != AF_INET && sfamily != AF_INET6) || port > 0)
705 hashdecl sockaddr_storage addr;
706#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
708 int size =
sizeof addr;
710 socklen_t size =
sizeof addr;
713 if (getsockname(sock, (
struct sockaddr *)&addr, (socklen_t *)&size) < 0)
716 port = q_get_port_from_addr((
const struct sockaddr *)&addr);
730 size_t offset = hdr.
size();
735 q_fix_decimal(&hdr, offset);
752 DLLLOCAL
static void do_headers(
QoreString& hdr,
const QoreHashNode* headers,
size_t size,
bool addsize =
true) {
760 const char* key = hi.getKey();
761 if (!size && addsize) {
762 if (!strcasecmp(key,
"transfer-encoding")) {
764 }
else if (!strcasecmp(key,
"content-type")
770 if ((addsize || size) && !strcasecmp(key,
"content-length")) {
777 do_header(key, hdr, li.getValue());
779 do_header(key, hdr, v);
783 if (size || addsize) {
784 hdr.
sprintf(
"Content-Length: %zu\r\n", size);
791 DLLLOCAL
int listen(
int backlog = 20) {
792 if (sock == QORE_INVALID_SOCKET)
797 if (::listen(sock, backlog)) {
804 return ::listen(sock, backlog);
808 DLLLOCAL
int accept_intern(
ExceptionSink* xsink,
struct sockaddr *addr, socklen_t *size,
int timeout_ms = -1) {
812 if (timeout_ms >= 0 && !isDataAvailable(timeout_ms,
"accept", xsink)) {
819 int rc = ::accept(sock, addr, size);
820 if (rc != QORE_INVALID_SOCKET)
824 if (sock_get_error() == EINTR)
827 qore_socket_error(xsink,
"SOCKET-ACCEPT-ERROR",
"error in accept()", 0, 0, 0, addr);
835 if (sock == QORE_INVALID_SOCKET) {
836 xsink->
raiseException(
"SOCKET-NOT-OPEN",
"socket must be opened, bound, and in a listening state before "
837 "new connections can be accepted");
842 se_in_op(
"Socket",
"accept", xsink);
845 se_in_op_thread(
"Socket",
"accept", xsink);
846 return QSE_IN_OP_THREAD;
850 if (sfamily == AF_UNIX) {
852 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"UNIX sockets are not available under Windows");
855 hashdecl sockaddr_un addr_un;
857#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
860 int size =
sizeof(
hashdecl sockaddr_un);
862 socklen_t size =
sizeof(
hashdecl sockaddr_un);
864 rc = accept_intern(xsink, (
struct sockaddr *)&addr_un, (socklen_t *)&size, timeout_ms);
867 if (rc >= 0 && source) {
869 addr->
sprintf(
"UNIX socket: %s", socketname.c_str());
870 source->priv->setAddress(addr);
871 source->priv->setHostName(
"localhost");
874 }
else if (sfamily == AF_INET || sfamily == AF_INET6) {
875 hashdecl sockaddr_storage addr_in;
876#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
879 int size =
sizeof(addr_in);
881 socklen_t size =
sizeof(addr_in);
884 rc = accept_intern(xsink, (
struct sockaddr *)&addr_in, (socklen_t *)&size, timeout_ms);
887 if (rc >= 0 && source) {
888 char host[NI_MAXHOST + 1];
889 char service[NI_MAXSERV + 1];
891 if (!getnameinfo((
struct sockaddr *)&addr_in, qore_get_in_len((
struct sockaddr *)&addr_in), host,
892 sizeof(host), service,
sizeof(service), NI_NUMERICSERV)) {
893 source->priv->setHostName(host);
897 char ifname[INET6_ADDRSTRLEN];
898 if (inet_ntop(addr_in.ss_family, qore_get_in_addr((
struct sockaddr *)&addr_in), ifname,
901 source->priv->setAddress(ifname);
906 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"do not know how to accept connections with address "
907 "family %d", sfamily);
913 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_SOCKET)
const {
932 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
935 event_queue->deref(xsink);
936 event_queue =
nullptr;
939 warn_queue->deref(xsink);
940 warn_queue =
nullptr;
941 if (warn_callback_arg) {
942 warn_callback_arg.
discard(xsink);
943 warn_callback_arg.
clear();
953 event_queue->deref(xsink);
957 event_data = with_data;
960 DLLLOCAL
void do_start_ssl_event() {
962 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_START_SSL));
966 DLLLOCAL
void do_ssl_established_event() {
971 event_queue->pushAndTakeRef(h);
975 DLLLOCAL
void do_connect_event(
int af,
const struct sockaddr* addr,
const char* target,
976 const char* service =
nullptr,
int prt = -1) {
985 q_af_to_hash(af, *h,
nullptr);
991 event_queue->pushAndTakeRef(h);
995 DLLLOCAL
void do_connected_event() {
997 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CONNECTED));
1001 DLLLOCAL
void do_data_event_intern(
int event,
int source,
const QoreStringNode& str)
const {
1002 assert(event_queue && event_data && str.
size());
1005 event_queue->pushAndTakeRef(h.release());
1008 DLLLOCAL
void do_data_event(
int event,
int source,
const QoreStringNode& str)
const {
1009 if (event_queue && event_data && str.
size()) {
1010 do_data_event_intern(event, source, str);
1014 DLLLOCAL
void do_data_event(
int event,
int source,
const BinaryNode& b)
const {
1015 if (event_queue && event_data && b.
size()) {
1018 event_queue->pushAndTakeRef(h.release());
1022 DLLLOCAL
void do_data_event(
int event,
int source,
const void* data,
size_t size)
const {
1023 if (event_queue && event_data && size) {
1028 event_queue->pushAndTakeRef(h.release());
1032 DLLLOCAL
void do_header_event(
int event,
int source,
const QoreHashNode& hdr)
const {
1033 if (event_queue && event_data && !hdr.
empty()) {
1036 event_queue->pushAndTakeRef(h.release());
1040 DLLLOCAL
void do_chunked_read(
int event,
size_t bytes,
size_t total_read,
int source) {
1043 if (event == QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED)
1047 h->
setKeyValue(
"total_read", total_read,
nullptr);
1048 event_queue->pushAndTakeRef(h);
1052 DLLLOCAL
void do_read_http_header(
int event,
const QoreHashNode* headers,
int source) {
1056 event_queue->pushAndTakeRef(h);
1060 DLLLOCAL
void do_send_http_message_event(
const QoreString& str,
const QoreHashNode* headers,
int source) {
1062 QoreHashNode* h = getEvent(QORE_EVENT_HTTP_SEND_MESSAGE, source);
1066 event_queue->pushAndTakeRef(h);
1070 DLLLOCAL
void do_close_event() {
1072 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
1076 DLLLOCAL
void do_read_event(
size_t bytes_read,
size_t total_read,
size_t bufsize = 0,
int source = QORE_SOURCE_SOCKET) {
1079 QoreHashNode* h = getEvent(QORE_EVENT_PACKET_READ, source);
1081 h->
setKeyValue(
"total_read", total_read,
nullptr);
1084 h->
setKeyValue(
"total_to_read", bufsize,
nullptr);
1085 event_queue->pushAndTakeRef(h);
1089 DLLLOCAL
void do_send_event(
int bytes_sent,
int total_sent,
int bufsize) {
1094 h->
setKeyValue(
"total_sent", total_sent,
nullptr);
1095 h->
setKeyValue(
"total_to_send", bufsize,
nullptr);
1096 event_queue->pushAndTakeRef(h);
1100 DLLLOCAL
void do_resolve_event(
const char* host,
const char* service = 0) {
1103 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_LOOKUP);
1108 event_queue->pushAndTakeRef(h);
1112 DLLLOCAL
void do_resolved_event(
const struct sockaddr* addr) {
1115 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_RESOLVED);
1121 int prt = q_get_port_from_addr(addr);
1124 q_af_to_hash(addr->sa_family, *h,
nullptr);
1125 event_queue->pushAndTakeRef(h);
1129 DLLLOCAL
int64 getObjectIDForEvents()
const {
1133 DLLLOCAL
int connectUNIX(
const char* p,
int sock_type,
int protocol,
ExceptionSink* xsink) {
1136 QORE_TRACE(
"connectUNIX()");
1139 xsink->
raiseException(
"SOCKET-CONNECTUNIX-ERROR",
"UNIX sockets are not available under Windows");
1145 printd(5,
"qore_socket_private::connectUNIX(%s)\n", p);
1147 hashdecl sockaddr_un addr;
1149 addr.sun_family = AF_UNIX;
1151 strncpy(addr.sun_path, p,
sizeof(addr.sun_path) - 1);
1152 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1153 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_SOCKET_ERROR) {
1154 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"error connecting to UNIX socket: '%s'", p);
1158 do_connect_event(AF_UNIX, (sockaddr*)&addr, p);
1160 if (!::connect(sock, (
const sockaddr *)&addr,
sizeof(
struct sockaddr_un)))
1164 if (sock_get_error() == EINTR)
1170 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, p);
1176 socketname = addr.sun_path;
1179 do_connected_event();
1191 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
const char* cname,
const char* mname,
1194 assert(read || write);
1195 if (sock == QORE_INVALID_SOCKET) {
1196 se_not_open(cname, mname, xsink,
"asyncIoWait");
1200 return asyncIoWait(timeout_ms, read, write, xsink);
1203 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
ExceptionSink* xsink)
const {
1205#if defined HAVE_POLL
1206 return poll_intern(xsink, timeout_ms, read, write);
1207#elif defined HAVE_SELECT
1208 return select_intern(xsink, timeout_ms, read, write);
1210#error no async socket operations supported
1214#if defined HAVE_POLL
1215 DLLLOCAL
int poll_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1222 pollfd fds = {sock, arg, 0};
1224 rc = ::poll(&fds, 1, timeout_ms);
1225 if (rc == -1 && errno == EINTR)
1230 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"poll(2) returned an error");
1231 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
1236#elif defined HAVE_SELECT
1237 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1238 bool aborted =
false;
1239 int rc = select_intern(xsink, timeout_ms, read, write, aborted);
1240 if (rc != QORE_SOCKET_ERROR && aborted)
1245 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write,
bool& aborted)
const {
1252 if (sock >= FD_SETSIZE) {
1253 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);
1257 hashdecl timeval tv;
1268 tv.tv_sec = timeout_ms / 1000;
1269 tv.tv_usec = (timeout_ms % 1000) * 1000;
1271 fd_set* readfd = read ? &sfs : 0;
1272 fd_set* writefd = write ? &sfs : 0;
1274 rc = select(sock + 1, readfd, writefd, &err, &tv);
1276 if (rc != QORE_SOCKET_ERROR) {
1277 if (FD_ISSET(sock, &err))
1281 if (sock_get_error() != EINTR)
1284 if (rc == QORE_SOCKET_ERROR) {
1287 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"select(2) returned an error");
1294 DLLLOCAL
bool tryReadSocketData(
const char* mname,
ExceptionSink* xsink) {
1299 return asyncIoWait(0,
true,
false,
"Socket", mname, xsink);
1303 int rc = ssl->doSSLRW(xsink, mname, rbuf, 1, 0, PEEK,
false);
1304 if (*xsink || (rc == QSE_TIMEOUT)) {
1307 return rc > 0 ? true :
false;
1310 DLLLOCAL
bool isSocketDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1311 return asyncIoWait(timeout_ms,
true,
false,
"Socket", mname, xsink);
1314 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1317 return isSocketDataAvailable(timeout_ms, mname, xsink);
1320 DLLLOCAL
bool isWriteFinished(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1321 return asyncIoWait(timeout_ms,
false,
true,
"Socket", mname, xsink);
1324 DLLLOCAL
int close_and_exit() {
1325 if (sock != QORE_INVALID_SOCKET)
1330 DLLLOCAL
int connectINETTimeout(
int timeout_ms,
const struct sockaddr* ai_addr,
size_t ai_addrlen,
1333 PrivateQoreSocketTimeoutHelper toh(
this,
"connect");
1336 if (!::connect(sock, ai_addr, ai_addrlen))
1340 if (sock_get_error() != EAGAIN) {
1341 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1349 if (errno != EINPROGRESS)
1358 bool aborted =
false;
1359 int rc = select_intern(xsink, timeout_ms,
false,
true, aborted);
1366 if (rc != QORE_SOCKET_ERROR && aborted) {
1367 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1371 int rc = asyncIoWait(timeout_ms,
false,
true,
"Socket",
"connectINETTimeout", xsink);
1377 if (rc == QORE_SOCKET_ERROR && sock_get_error() != EINTR) {
1379 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in asyncIoWait() with "
1380 "Socket::connect() with timeout", 0, 0, 0, ai_addr);
1382 }
else if (rc > 0) {
1383 return checkConnected(xsink,
nullptr, ai_addr, only_timeout);
1387 concat_target(*(*desc), ai_addr);
1397 DLLLOCAL
int checkConnected(
ExceptionSink* xsink,
const char* hostsvc,
const struct sockaddr* ai_addr =
nullptr,
1398 bool only_timeout =
false) {
1402 socklen_t lon =
sizeof(int);
1405 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (GETSOCKOPT_ARG_4)(&val), &lon) == QORE_SOCKET_ERROR) {
1406 if (!only_timeout) {
1407 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
nullptr,
1418 qore_socket_error_intern(val, xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
1427 DLLLOCAL
void confirmConnected(
const char* host) {
1428 do_connected_event();
1432 client_target = host;
1436 DLLLOCAL
int sock_errno_err(
const char* err,
const char* desc,
ExceptionSink* xsink) {
1438 qore_socket_error(xsink, err, desc);
1442 DLLLOCAL
int set_non_blocking(
bool non_blocking,
ExceptionSink* xsink) {
1445 if (sock == QORE_INVALID_SOCKET) {
1451 u_long mode = non_blocking ? 1 : 0;
1452 int rc = ioctlsocket(sock, FIONBIO, &mode);
1453 if (check_windows_rc(rc)) {
1454 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in ioctlsocket(FIONBIO)", xsink);
1460 if ((arg = fcntl(sock, F_GETFL, 0)) < 0) {
1461 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() getting socket descriptor status "
1471 if (fcntl(sock, F_SETFL, arg) < 0) {
1472 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() setting socket descriptor status "
1481 DLLLOCAL
int connectINET(
const char* host,
const char* service,
int timeout_ms,
ExceptionSink* xsink,
1482 int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0) {
1484 family = q_get_af(family);
1485 type = q_get_sock_type(type);
1487 QORE_TRACE(
"qore_socket_private::connectINET()");
1492 printd(5,
"qore_socket_private::connectINET(%s:%s, %dms)\n", host, service, timeout_ms);
1494 do_resolve_event(host, service);
1497 if (ai.
getInfo(xsink, host, service, family, 0, type, protocol))
1504 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1505 do_resolved_event(p->ai_addr);
1507 int prt = q_get_port_from_addr(aip->ai_addr);
1509 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1510 if (!connectINETIntern(host, service, p->ai_family, p->ai_addr, p->ai_addrlen, p->ai_socktype,
1511 p->ai_protocol, prt, timeout_ms, xsink,
true)) {
1520 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1525 DLLLOCAL
int connectINETIntern(
const char* host,
const char* service,
int ai_family,
struct sockaddr* ai_addr,
1526 size_t ai_addrlen,
int ai_socktype,
int ai_protocol,
int prt,
int timeout_ms,
ExceptionSink* xsink,
1527 bool only_timeout =
false) {
1529 printd(5,
"qore_socket_private::connectINETIntern() host: %s service: %s family: %d timeout_ms: %d\n", host,
1530 service, ai_family, timeout_ms);
1531 if ((sock = socket(ai_family, ai_socktype, ai_protocol)) == QORE_INVALID_SOCKET) {
1532 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"cannot establish a connection to %s:%s", host,
1543 if (timeout_ms >= 0) {
1545 if (set_non_blocking(
true, xsink))
1546 return close_and_exit();
1548 do_connect_event(ai_family, ai_addr, host, service, prt);
1550 rc = connectINETTimeout(timeout_ms, ai_addr, ai_addrlen, xsink, only_timeout);
1554 if (set_non_blocking(
false, xsink))
1555 return close_and_exit();
1557 do_connect_event(ai_family, ai_addr, host, service, prt);
1560 rc = ::connect(sock, ai_addr, ai_addrlen);
1563 if (!rc || sock_get_error() != EINTR)
1569 if (!only_timeout || errno == ETIMEDOUT)
1570 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1572 return close_and_exit();
1575 sfamily = ai_family;
1576 stype = ai_socktype;
1577 sprot = ai_protocol;
1582 confirmConnected(host);
1586 DLLLOCAL
int upgradeClientToSSLIntern(
ExceptionSink* xsink,
const char* mname,
const char* sni_target_host,
1589 SSLSocketHelperHelper sshh(
this,
true);
1592 do_start_ssl_event();
1594 if (!sni_target_host && !client_target.empty()) {
1595 sni_target_host = client_target.c_str();
1597 if ((rc = ssl->setClient(xsink, mname, sni_target_host, sock, cert, pkey))
1598 || ssl->connect(mname, timeout_ms,
1601 return rc ? rc : -1;
1603 do_ssl_established_event();
1608 DLLLOCAL
int upgradeServerToSSLIntern(
ExceptionSink* xsink,
const char* mname,
int timeout_ms,
1612 SSLSocketHelperHelper sshh(
this,
true);
1614 do_start_ssl_event();
1615 if (ssl->setServer(xsink, mname, sock, cert, pkey) || ssl->accept(mname, timeout_ms, xsink)) {
1619 do_ssl_established_event();
1625 DLLLOCAL
int openUNIX(
int sock_type = SOCK_STREAM,
int protocol = 0) {
1626 if (sock != QORE_INVALID_SOCKET)
1629 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_INVALID_SOCKET) {
1641 DLLLOCAL
int openINET(
int family = AF_INET,
int sock_type = SOCK_STREAM,
int protocol = 0) {
1642 if (sock != QORE_INVALID_SOCKET)
1645 if ((sock = socket(family, sock_type, protocol)) == QORE_INVALID_SOCKET)
1655 DLLLOCAL
int reuse(
int opt) {
1657 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_ARG_4)&opt,
sizeof(
int));
1661 DLLLOCAL
int bindIntern(
struct sockaddr* ai_addr,
size_t ai_addrlen,
int prt,
bool reuseaddr,
ExceptionSink* xsink = 0) {
1664 if ((::bind(sock, ai_addr, ai_addrlen)) == QORE_SOCKET_ERROR) {
1666 qore_socket_error(xsink,
"SOCKET-BIND-ERROR",
"error in bind()", 0, 0, 0, ai_addr);
1676#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1678 int len = ai_addrlen;
1680 socklen_t len = ai_addrlen;
1683 if (getsockname(sock, ai_addr, &len))
1686 port = q_get_port_from_addr(ai_addr);
1692 DLLLOCAL
int bindUNIX(
ExceptionSink* xsink,
const char* name,
int socktype = SOCK_STREAM,
int protocol = 0) {
1695 xsink->
raiseException(
"SOCKET-BINDUNIX-ERROR",
"UNIX sockets are not available under Windows");
1701 if (openUNIX(socktype, protocol)) {
1702 xsink->
raiseErrnoException(
"SOCKET-BIND-ERROR", errno,
"error opening UNIX socket ('%s') for bind", name);
1706 hashdecl sockaddr_un addr;
1707 addr.sun_family = AF_UNIX;
1709 strncpy(addr.sun_path, name,
sizeof(addr.sun_path) - 1);
1710 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1712 if (bindIntern((sockaddr*)&addr,
sizeof(
struct sockaddr_un), -1,
false, xsink))
1716 socketname = addr.sun_path;
1723 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) {
1725 family = q_get_af(family);
1726 socktype = q_get_sock_type(socktype);
1731 do_resolve_event(name, service);
1732 if (ai.
getInfo(xsink, name, service, family, AI_PASSIVE, socktype, protocol))
1738 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1739 do_resolved_event(p->ai_addr);
1742 if (openINET(aip->ai_family, aip->ai_socktype, protocol)) {
1743 qore_socket_error(xsink,
"SOCKET-BINDINET-ERROR",
"error opening socket for bind", 0, name, service);
1747 int prt = q_get_port_from_addr(aip->ai_addr);
1751 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1752 if (!bindIntern(p->ai_addr, p->ai_addrlen, prt, reuseaddr)) {
1757 en = sock_get_raw_error();
1762 qore_socket_error_intern(en, xsink,
"SOCKET-BIND-ERROR",
"error binding on socket", 0, name, service);
1769 if (sock == QORE_INVALID_SOCKET) {
1770 se_not_open(
"Socket",
"getPeerInfo", xsink);
1774 hashdecl sockaddr_storage addr;
1775 socklen_t len =
sizeof addr;
1776 if (getpeername(sock, (
struct sockaddr*)&addr, &len)) {
1777 qore_socket_error(xsink,
"SOCKET-GETPEERINFO-ERROR",
"error in getpeername()");
1781 return getAddrInfo(addr, len, host_lookup);
1787 if (sock == QORE_INVALID_SOCKET) {
1788 se_not_open(
"Socket",
"getSocketInfo", xsink);
1792 hashdecl sockaddr_storage addr;
1793#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1795 int len =
sizeof addr;
1797 socklen_t len =
sizeof addr;
1800 if (getsockname(sock, (
struct sockaddr*)&addr, &len)) {
1801 qore_socket_error(xsink,
"SOCKET-GETSOCKETINFO-ERROR",
"error in getsockname()");
1805 return getAddrInfo(addr, len, host_lookup);
1808 DLLLOCAL
QoreHashNode* getAddrInfo(
const struct sockaddr_storage& addr, socklen_t len,
bool host_lookup =
true)
const {
1811 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1813 char host[NI_MAXHOST + 1];
1815 if (!getnameinfo((
struct sockaddr*)&addr, qore_get_in_len((
struct sockaddr*)&addr), host,
sizeof(host), 0, 0, 0)) {
1823 char ifname[INET6_ADDRSTRLEN];
1824 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr*)&addr), ifname,
sizeof(ifname))) {
1831 if (addr.ss_family == AF_INET) {
1832 hashdecl sockaddr_in* s = (
hashdecl sockaddr_in*)&addr;
1833 tport = ntohs(s->sin_port);
1835 hashdecl sockaddr_in6* s = (
hashdecl sockaddr_in6*)&addr;
1836 tport = ntohs(s->sin6_port);
1842 else if (addr.ss_family == AF_UNIX) {
1843 assert(!socketname.empty());
1859 hashdecl sockaddr_storage addr;
1861 socklen_t len =
sizeof addr;
1862 if (getpeername(sock, (
struct sockaddr*)&addr, &len))
1865 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1867 char ifname[INET6_ADDRSTRLEN];
1868 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr *)&addr), ifname,
sizeof(ifname))) {
1873 char host[NI_MAXHOST + 1];
1874 if (!getnameinfo((
struct sockaddr *)&addr, qore_get_in_len((
struct sockaddr *)&addr), host,
sizeof(host),
1880 else if (addr.ss_family == AF_UNIX) {
1882 hashdecl sockaddr_un *addr_un = (
hashdecl sockaddr_un *)&addr;
1883 astr->
sprintf(
"UNIX socket: %s", addr_un->sun_path);
1896 DLLLOCAL
int readByteFromBuffer(
char& output) {
1898 assert(sock != QORE_INVALID_SOCKET);
1905 output = *(rbuf + bufoffset);
1917 DLLLOCAL ssize_t brecv(
ExceptionSink* xsink,
const char* meth,
char*& buf,
size_t bs,
int flags,
1918 int timeout,
bool do_event =
true,
bool suppress_exception =
false) {
1921 assert(sock != QORE_INVALID_SOCKET);
1926 buf = rbuf + bufoffset;
1945 if (timeout >= 0 && !isDataAvailable(timeout, meth, xsink)) {
1949 if (!suppress_exception) {
1950 se_timeout(
"Socket", meth, timeout, xsink);
1957 rc = ::recv(sock, rbuf, DEFAULT_SOCKET_BUFSIZE, flags);
1958 if (rc == QORE_SOCKET_ERROR) {
1960 if (errno == EINTR) {
1964 if (errno == ECONNRESET) {
1965 if (!suppress_exception) {
1966 se_closed(
"Socket", meth, xsink);
1971 if (!suppress_exception) {
1972 qore_socket_error(xsink,
"SOCKET-RECV-ERROR",
"error in recv()", meth);
1984 rc = ssl->read(xsink, meth, rbuf, DEFAULT_SOCKET_BUFSIZE, timeout, suppress_exception);
1992 if (rc > (ssize_t)bs) {
2000 do_read_event(rc, rc);
2004 if (!rc && isOpen() && errno != EAGAIN && errno != EINPROGRESS) {
2014 bool exit_early =
false) {
2017 if (sock == QORE_INVALID_SOCKET) {
2018 se_not_open(
"Socket", meth, xsink,
"readHTTPData");
2023 PrivateQoreSocketThroughputHelper th(
this,
false);
2038 rc = brecv(xsink, meth, buf, 1, 0, timeout,
false);
2049 se_closed(
"Socket", meth, xsink);
2051 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"socket closed on remote end "
2052 "while reading header data after reading " QSD
" byte%s", count, count == 1 ?
"" :
"s");
2058 if (++count == QORE_MAX_HEADER_SIZE) {
2059 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"header size cannot exceed " QSD
" bytes", count);
2070 if (exit_early && hdr->
empty())
2077 }
else if (c ==
'\r') {
2092 case 0: hdr->concat(
'\r');
break;
2093 case 1: hdr->concat(
"\r\n");
break;
2094 case 2: hdr->concat(
"\r\n\r");
break;
2095 case 3: hdr->concat(
'\n');
break;
2104 th.finalize(hdr->
size());
2105 return hdr.release();
2109 int source = QORE_SOURCE_SOCKET) {
2111 if (sock == QORE_INVALID_SOCKET) {
2112 se_not_open(
"Socket",
"recv", xsink,
"recv");
2118 se_in_op(
"Socket",
"recv", xsink);
2121 se_in_op_thread(
"Socket",
"recv", xsink);
2125 PrivateQoreSocketThroughputHelper th(
this,
false);
2127 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2134 rc = brecv(xsink,
"recv", buf, bs, 0, timeout,
false);
2140 printd(5,
"qore_socket_private::recv(" QSD
", %d) bs=" QSD
", br=" QSD
", rc=" QSD
", errno: %d "
2141 "(%s)\n", bufsize, timeout, bs, str->
size(), rc, errno, strerror(errno));
2149 do_read_event(rc, str->
size(), bufsize, source);
2153 if (str->
size() >= (
size_t)bufsize)
2155 if ((bufsize - str->
size()) < bs)
2156 bs = bufsize - str->
size();
2160 printd(5,
"qore_socket_private::recv() received " QSD
" byte(s), bufsize=" QSD
", strlen=" QSD
" str='%s'\n",
2161 str->
size(), bufsize, (str ? str->
strlen() : 0), str ? str->c_str() :
"n/a");
2167 th.finalize(str->
size());
2174 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2176 return str.release();
2180 int source = QORE_SOURCE_SOCKET) {
2182 if (sock == QORE_INVALID_SOCKET) {
2183 se_not_open(
"Socket",
"recv", xsink,
"recvAll");
2189 se_in_op(
"Socket",
"recv", xsink);
2192 se_in_op_thread(
"Socket",
"recv", xsink);
2196 PrivateQoreSocketThroughputHelper th(
this,
false);
2202 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2211 do_read_event(rc, rc);
2214 if (isDataAvailable(0,
"recv", xsink)) {
2216 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false,
true);
2225 do_read_event(rc, str->
size());
2226 }
while (isDataAvailable(0,
"recv", xsink));
2229 th.finalize(str->
size());
2237 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2239 return str.release();
2242 DLLLOCAL
int recv(
int fd, ssize_t size,
int timeout_ms,
ExceptionSink* xsink);
2245 int source = QORE_SOURCE_SOCKET) {
2247 if (sock == QORE_INVALID_SOCKET) {
2248 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinary");
2254 se_in_op(
"Socket",
"recvBinary", xsink);
2257 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2261 PrivateQoreSocketThroughputHelper th(
this,
false);
2263 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2269 rc = brecv(xsink,
"recvBinary", buf, bs, 0, timeout);
2276 if (b->
size() >= (
size_t)bufsize)
2278 if ((bufsize - b->
size()) < bs)
2279 bs = bufsize - b->
size();
2283 th.finalize(b->
size());
2293 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2295 printd(5,
"qore_socket_private::recvBinary() received " QSD
" byte(s), bufsize=" QSD
", blen=" QSD
"\n",
2301 int source = QORE_SOURCE_SOCKET) {
2303 if (sock == QORE_INVALID_SOCKET) {
2304 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinaryAll");
2310 se_in_op(
"Socket",
"recvBinary", xsink);
2313 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2317 PrivateQoreSocketThroughputHelper th(
this,
false);
2324 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2333 do_read_event(rc, rc);
2336 while (isDataAvailable(0,
"recvBinary", xsink)) {
2337 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false,
true);
2347 do_read_event(rc, b->
size());
2350 th.finalize(b->
size());
2357 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2366 if (sock == QORE_INVALID_SOCKET) {
2367 se_not_open(
"Socket",
"recvToOutputStream", xsink);
2372 se_in_op(
"Socket",
"recvToOutputStream", xsink);
2375 se_in_op_thread(
"Socket",
"recvToOutputStream", xsink);
2379 qore_socket_op_helper oh(
this);
2383 while (size < 0 || br < size) {
2385 int bn = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - br, DEFAULT_SOCKET_BUFSIZE);
2387 ssize_t rc = brecv(xsink,
"recvToOutputStream", buf, bn, 0, timeout);
2396 xsink->
raiseException(
"SOCKET-RECV-ERROR",
"Unexpected end of stream");
2402 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, buf, rc);
2408 os->
write(buf, rc, xsink);
2427 do_data_event(QORE_EVENT_HTTP_HEADERS_READ, source, **hdr);
2428 return hdr.release();
2432 ssize_t& rc,
int source,
const char* headers_raw_key =
"headers-raw") {
2441 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"remote closed the connection while reading the HTTP header");
2446 return processHttpHeaderString(xsink, hdr, info, source, headers_raw_key);
2451 QoreHashNode* info,
int source,
const char* headers_raw_key =
"headers-raw") {
2452 const char* buf = hdr->
c_str();
2454 if ((p = (
char*)strstr(buf,
"\r\n"))) {
2457 }
else if ((p = (
char*)strchr(buf,
'\n'))) {
2460 }
else if ((p = (
char*)strchr(buf,
'\r'))) {
2466 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"invalid header received with embedded nulls in "
2467 "Socket::readHTTPHeader()");
2472 if (!(t1 = (
char*)strstr(buf,
"HTTP/"))) {
2473 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"missing HTTP version string in "
2474 "first header line in Socket::readHTTPHeader()");
2481 int flags = CHF_PROCESS;
2488 flags |= CHF_HTTP11;
2494 const char* info_key;
2496 char* t2 = (
char*)strchr(buf + 8,
' ');
2499 if (isdigit(*(t2))) {
2501 if (strlen(t2) > 4) {
2508 info_key =
"response-uri";
2510 char* t2 = (
char*)strchr(buf,
' ');
2515 t1 = strchr(t2,
' ');
2523 info_key =
"request-uri";
2524 flags |= CHF_REQUEST;
2528 if (info || (event_queue && event_data)) {
2530 if (info && event_queue && event_data) {
2533 if (event_queue && event_data) {
2534 do_data_event_intern(QORE_EVENT_SOCKET_DATA_READ, source, **status_line);
2537 info->
setKeyValue(info_key, *status_line,
nullptr);
2539 status_line.release();
2542 bool close = convertHeaderToHash(*h, p, flags, info, &http_exp_chunked_body, headers_raw_key);
2543 do_read_http_header(QORE_EVENT_HTTP_MESSAGE_RECEIVED, *h, source);
2546 if ((flags & CHF_REQUEST) && info) {
2554 DLLLOCAL
int runHeaderCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2556 bool send_aborted =
false,
QoreObject* obj =
nullptr) {
2565 arg->
setKeyValue(
"send_aborted", send_aborted, xsink);
2566 args->push(arg,
nullptr);
2569 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2572 DLLLOCAL
int runTrailerCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2575 if (runCallback(xsink, cname, mname, rv, callback, l,
nullptr))
2586 xsink->
raiseException(
"HTTP-TRAILER-ERROR",
"chunked callback returned type '%s'; expecting 'hash' "
2593 DLLLOCAL
int runDataCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2600 args->push(arg,
nullptr);
2603 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2619 return *xsink ? -1 : 0;
2622 DLLLOCAL
int sendHttpChunkedWithCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2624 bool* aborted =
nullptr) {
2626 assert(!aborted || !(*aborted));
2628 if (sock == QORE_INVALID_SOCKET) {
2629 se_not_open(cname, mname, xsink,
"sendHttpChunkedWithCallback");
2630 return QSE_NOT_OPEN;
2634 se_in_op(cname, mname, xsink);
2637 se_in_op_thread(cname, mname, xsink);
2641 PrivateQoreSocketThroughputHelper th(
this,
true);
2644 bool nb = (timeout_ms >= 0);
2646 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2650 qore_socket_op_helper oh(
this);
2659 bool data_available = tryReadSocketData(mname, xsink);
2661 if (data_available || *xsink) {
2663 return *xsink ? -1 : 0;
2669 rc = runCallback(xsink, cname, mname, res, send_callback, &l);
2678 const char* data_ptr =
nullptr;
2679 size_t data_size = 0;
2681 switch (res->getType()) {
2689 data_ptr = str->
c_str();
2690 data_size = str->
size();
2702 data_ptr =
static_cast<const char*
>(b->
getPtr());
2703 data_size = b->
size();
2715 const char* key = hi.getKey();
2722 do_header(key, buf, li.getValue());
2724 do_header(key, buf, v);
2735 xsink->
raiseException(
"SOCKET-CALLBACK-ERROR",
"HTTP chunked data callback returned type '%s'; expecting one of: 'string', 'binary', 'hash', 'nothing' (or 'NULL')", res->getTypeName());
2741 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2747 if (data_ptr && data_size) {
2748 rc = sendIntern(xsink, cname, mname, data_ptr, data_size, timeout_ms, total,
true);
2753 if (buf.
empty() && (!data_ptr || !data_size)) {
2754 buf.
set(
"0\r\n\r\n");
2758 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2764 switch (res->getType()) {
2767 if (!str->
empty()) {
2768 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *str);
2776 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *b);
2783 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, source, *h);
2791 if (aborted && *xsink) {
2792 bool data_available = tryReadSocketData(mname, xsink);
2794 if (data_available) {
2796 return *xsink ? -1 : 0;
2805 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2811 return rc < 0 || sock == QORE_INVALID_SOCKET ? -1 : 0;
2815 DLLLOCAL ssize_t sendIntern(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2816 int timeout_ms,
int64& total,
bool stream =
false) {
2822 bool nb = (timeout_ms >= 0);
2827 rc = ssl->write(mname, buf + bs, size - bs, timeout_ms, xsink);
2830 rc = ::send(sock, buf + bs, size - bs, 0);
2837 if (nb && (errno == EAGAIN
2839 || errno == EWOULDBLOCK
2842 if (!isWriteFinished(timeout_ms, mname, xsink)) {
2845 se_timeout(
"Socket", mname, timeout_ms, xsink);
2851 if (errno != EINTR) {
2853 xsink->
raiseErrnoException(
"SOCKET-SEND-ERROR", errno,
"error while executing %s::%s()", cname, mname);
2857 if (!stream && errno == EPIPE) {
2862 if (!stream && errno == ECONNRESET) {
2875 if (rc < 0 || sock == QORE_INVALID_SOCKET) {
2879 do_send_event(rc, bs, size);
2888 DLLLOCAL
int send(
int fd, ssize_t size,
int timeout_ms,
ExceptionSink* xsink);
2891 DLLLOCAL
int send(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2892 int timeout_ms = -1,
int source = QORE_SOURCE_SOCKET) {
2894 if (sock == QORE_INVALID_SOCKET) {
2895 se_not_open(cname, mname, xsink,
"send");
2896 return QSE_NOT_OPEN;
2900 se_in_op(cname, mname, xsink);
2903 se_in_op_thread(cname, mname, xsink);
2910 PrivateQoreSocketThroughputHelper th(
this,
true);
2913 bool nb = (timeout_ms >= 0);
2915 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2921 ssize_t rc = sendIntern(xsink, cname, mname, buf, size, timeout_ms, total);
2924 if (rc > 0 && source > 0) {
2925 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, buf, size);
2928 return rc < 0 || sock == QORE_INVALID_SOCKET ? rc : 0;
2933 if (sock == QORE_INVALID_SOCKET) {
2934 se_not_open(
"Socket",
"sendFromInputStream", xsink);
2939 se_in_op(
"Socket",
"sendFromInputStream", xsink);
2942 se_in_op_thread(
"Socket",
"sendFromInputStream", xsink);
2946 qore_socket_op_helper oh(
this);
2948 PrivateQoreSocketThroughputHelper th(
this,
true);
2951 bool nb = (timeout >= 0);
2953 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2957 char buf[DEFAULT_SOCKET_BUFSIZE];
2960 while (size < 0 || sent < size) {
2961 int64 toRead = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - sent, DEFAULT_SOCKET_BUFSIZE);
2965 r = is->
read(buf, toRead, xsink);
2974 xsink->
raiseException(
"SOCKET-SEND-ERROR",
"Unexpected end of stream");
2980 ssize_t rc = sendIntern(xsink,
"Socket",
"sendFromInputStream", buf, r, timeout, total);
2984 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, QORE_SOURCE_SOCKET, buf, r);
2991 if (sock == QORE_INVALID_SOCKET) {
2992 se_not_open(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
2997 se_in_op(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
3000 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
3004 qore_socket_op_helper oh(
this);
3006 PrivateQoreSocketThroughputHelper th(
this,
true);
3009 bool nb = (timeout >= 0);
3011 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
3017 buf->preallocate(max_chunk_size);
3023 r = is->
read((
void*)buf->getPtr(),
sizeof(max_chunk_size), xsink);
3030 str.
sprintf(
"%x\r\n", (
int)r);
3031 int rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
3035 bool trailers =
false;
3039 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", (
const char*)buf->getPtr(), r, timeout, total,
true);
3042 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, QORE_SOURCE_SOCKET, buf->getPtr(), r);
3043 }
else if (trailer_callback) {
3047 if (runTrailerCallback(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", *trailer_callback, l, h))
3051 do_headers(str, *h, 0,
false);
3053 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
3057 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, **h);
3065 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
3079 if (sock == QORE_INVALID_SOCKET) {
3080 se_not_open(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3085 se_in_op(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3088 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3098 const char* key = hi.getKey();
3103 do_header(key, buf, li.getValue());
3106 do_header(key, buf, v);
3111 sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyTrailer", buf.
c_str(), buf.
size(), timeout, total,
true);
3113 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, *headers);
3117 DLLLOCAL
void getSendHttpMessageHeaders(
QoreString& hdr,
QoreHashNode* info,
const char* method,
const char* path,
3118 const char* http_version,
const QoreHashNode* headers,
size_t size,
int source) {
3120 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3127 getSendHttpMessageHeadersCommon(hdr, info, headers, size, source);
3131 size_t size,
int source) {
3133 do_send_http_message_event(hdr, headers, source);
3138 do_headers(hdr, headers, size);
3142 const char* method,
const char* path,
const char* http_version,
const QoreHashNode* headers,
3150 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3157 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3158 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3170 hdr.
sprintf(
"HTTP/%s %03d %s", http_version, code, desc);
3178 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3179 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3188 assert(!(data && send_callback));
3189 assert(!(data && input_stream));
3190 assert(!(send_callback && input_stream));
3193 do_send_http_message_event(hdr, headers, source);
3198 do_headers(hdr, headers, size && data ? size : 0);
3204 if ((rc = send(xsink, cname, mname, hdr.
c_str(), hdr.
size(), timeout_ms, -1)))
3209 int rc = send(xsink, cname, mname, (
char*)data, size, timeout_ms, -1);
3212 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, *body);
3214 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, data, size);
3218 }
else if (send_callback) {
3220 assert(!aborted || !(*aborted));
3221 return sendHttpChunkedWithCallback(xsink, cname, mname, *send_callback, *l, source, timeout_ms, aborted);
3222 }
else if (input_stream) {
3224 sendHttpChunkedBodyFromInputStream(input_stream, max_chunk_size, timeout_ms, xsink, l, trailer_callback);
3225 return *xsink ? -1 : 0;
3236 if (sock == QORE_INVALID_SOCKET) {
3237 se_not_open(cname,
"readHTTPChunkedBodyBinary", xsink);
3242 se_in_op(cname,
"readHTTPChunkedBodyBinary", xsink);
3245 se_in_op_thread(cname,
"readHTTPChunkedBodyBinary", xsink);
3250 if (http_exp_chunked_body)
3251 http_exp_chunked_body =
false;
3253 qore_socket_op_helper oh(
this);
3266 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 1, 0, timeout,
false);
3270 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3277 if (!state && c ==
'\r')
3279 else if (state && c ==
'\n')
3294 char* p = (
char*)strchr(str.
c_str(),
';');
3297 long size = strtol(str.
c_str(), 0, 16);
3298 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
size(), source);
3305 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3312 ssize_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3316 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, bs, 0, timeout,
false);
3322 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3327 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, buf, (
size_t)rc);
3331 os->
write(buf, rc, xsink);
3342 if (size - br < bs) {
3355 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 2 - br, 0, timeout,
false);
3359 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3366 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3368 if (recv_callback && !os) {
3369 if (runDataCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, *b,
true))
3376 assert(!recv_callback);
3393 if (!recv_callback && !os) {
3401 return recv_callback ? 0 : h.release();
3403 if (recv_callback) {
3406 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3407 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3410 if (recv_callback) {
3411 runHeaderCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, h->
empty() ?
nullptr : *h,
3412 info.release(), false, obj);
3424 if (sock == QORE_INVALID_SOCKET) {
3425 se_not_open(cname,
"readHTTPChunkedBody", xsink);
3430 se_in_op(cname,
"readHTTPChunkedBody", xsink);
3433 se_in_op_thread(cname,
"readHTTPChunkedBody", xsink);
3438 if (http_exp_chunked_body)
3439 http_exp_chunked_body =
false;
3441 qore_socket_op_helper oh(
this);
3454 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 1, 0, timeout,
false);
3458 se_closed(cname,
"readHTTPChunkedBody", xsink);
3465 if (!state && c ==
'\r')
3467 else if (state && c ==
'\n')
3481 char* p = (
char*)strchr(str.
c_str(),
';');
3484 ssize_t size = strtol(str.
c_str(), 0, 16);
3485 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
strlen(), source);
3491 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3501 ssize_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3506 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, bs, 0, timeout,
false);
3510 se_closed(cname,
"readHTTPChunkedBody", xsink);
3516 buf->concat(tbuf, rc);
3518 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, tbuf, (
size_t)rc);
3534 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 2 - br, 0, timeout,
false);
3538 se_closed(cname,
"readHTTPChunkedBody", xsink);
3545 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3547 if (recv_callback) {
3548 if (runDataCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, *buf,
true))
3561 if (!recv_callback) {
3569 return recv_callback ? 0 : h.release();
3571 if (recv_callback) {
3574 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3575 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3578 if (recv_callback) {
3579 runHeaderCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, h->
empty() ?
nullptr : *h,
3580 info.release(), false, obj);
3591 DLLLOCAL
static void do_accept_encoding(
char* t,
QoreHashNode& info) {
3600 while (*a && *a !=
';' && *a !=
',')
3604 l->push(str.release(),
nullptr);
3614 info.
setKeyValue(
"accept-encoding", l.release(), 0);
3617 DLLLOCAL
bool do_accept_charset(
char* t,
QoreHashNode& info) {
3618 bool acceptcharset =
false;
3633 if (*a ==
'u' || *a ==
'U') {
3635 if (*a ==
't' || *a ==
'T') {
3637 if (*a ==
'f' || *a ==
'F') {
3649 }
else if (*a ==
',') {
3653 }
else if (*a ==
';') {
3662 acceptcharset =
true;
3666 ac->concat(t, div - t);
3671 info.
setKeyValue(
"accept-charset", ac.release(), 0);
3672 acceptcharset =
true;
3676 return acceptcharset;
3681 bool* chunked =
nullptr,
const char* headers_raw_key =
"headers-raw") {
3682 bool close = !(flags & CHF_HTTP11);
3684 const char* senc =
nullptr;
3686 bool acceptcharset =
false;
3694 std::string raw_key;
3699 if ((p = strstr(buf,
"\r\n"))) {
3702 }
else if ((p = strchr(buf,
'\n'))) {
3705 }
else if ((p = strchr(buf,
'\r'))) {
3710 char* t = strchr(buf,
':');
3715 while (t && qore_isblank(*t))
3725 if (flags & CHF_PROCESS) {
3726 if (!strcmp(buf,
"connection")) {
3727 if (flags & CHF_HTTP11) {
3728 if (strcasestr(t,
"close"))
3731 if (strcasestr(t,
"keep-alive"))
3734 }
else if (!strcmp(buf,
"content-type")) {
3735 char* a = strcasestr(t,
"charset=");
3738 char* e = strchr(a + 8,
';');
3742 cs.
concat(a + 8, e - a - 8);
3751 size_t len = cs.
size();
3761 }
while (a > t && (*a ==
' ' || *a ==
';'));
3768 ct->concat(t, a - t + 1);
3774 info->
setKeyValue(
"body-content-type", ct.release(),
nullptr);
3780 info->
setKeyValue(
"body-content-type", val->refSelf(),
nullptr);
3783 }
else if (chunked && !strcmp(buf,
"transfer-encoding") && !strcasecmp(t,
"chunked")) {
3786 if (!strcmp(buf,
"accept-charset"))
3787 acceptcharset = do_accept_charset(t, *info);
3788 else if ((flags & CHF_REQUEST) && !strcmp(buf,
"accept-encoding"))
3789 do_accept_encoding(t, *info);
3794 if (raw_hdr && val) {
3795 val_copy = val->realCopy();
3799 hash_assignment_priv ha(*h, buf);
3800 if (!(*ha).isNothing()) {
3802 if ((*ha).getType() ==
NT_LIST) {
3806 l->
push(ha.swap(l),
nullptr);
3808 l->
push(val.release(),
nullptr);
3810 ha.assign(val.release(), 0);
3814 hash_assignment_priv ha(*raw_hdr, raw_key);
3815 if (!(*ha).isNothing()) {
3817 if ((*ha).getType() ==
NT_LIST) {
3821 l->
push(ha.swap(l),
nullptr);
3823 l->
push(val_copy.release(),
nullptr);
3825 ha.assign(val_copy.release(),
nullptr);
3829 if ((flags & CHF_PROCESS)) {
3833 if (info && !acceptcharset)
3840 DLLLOCAL
int recvix(
const char* meth,
int len,
void* targ,
int timeout_ms,
ExceptionSink* xsink) {
3842 if (sock == QORE_INVALID_SOCKET) {
3843 se_not_open(
"Socket", meth, xsink,
"recvix");
3844 return QSE_NOT_OPEN;
3848 se_in_op(
"Socket", meth, xsink);
3851 se_in_op_thread(
"Socket", meth, xsink);
3855 PrivateQoreSocketThroughputHelper th(
this,
false);
3860 ssize_t rc = brecv(xsink, meth, buf, len - br, 0, timeout_ms);
3862 do_read_error(rc, meth, timeout_ms, xsink);
3866 memcpy(targ, buf, rc);
3874 do_data_event(QORE_EVENT_SOCKET_DATA_READ, QORE_SOURCE_SOCKET, targ, br);
3880 if (warn_callback_arg) {
3881 warn_callback_arg.
discard(xsink);
3884 warn_queue->deref(xsink);
3885 warn_queue =
nullptr;
3887 tp_warning_bs = 0.0;
3893 int64 min_ms = 1000) {
3896 if (warning_ms <= 0 && warning_bs <= 0) {
3897 xsink->
raiseException(
"SOCKET-SETWARNINGQUEUE-ERROR",
"Socket::setWarningQueue() at least one of warning "
3898 "ms argument: " QLLD
" and warning B/s argument: " QLLD
" must be greater than zero; to clear, call "\
3899 "Socket::clearWarningQueue() with no arguments", warning_ms, warning_bs);
3909 warn_queue->
deref(xsink);
3910 warn_callback_arg.
discard(xsink);
3913 warn_queue = qholder.release();
3914 warn_callback_arg = holder.release();
3915 tl_warning_us = (
int64)warning_ms * 1000;
3916 tp_warning_bs = warning_bs;
3917 tp_us_min = min_ms * 1000;
3920 DLLLOCAL
void getUsageInfo(
QoreHashNode& h, qore_socket_private& s)
const {
3928 h.
setKeyValue(
"bytes_sent", tp_bytes_sent + s.tp_bytes_sent, 0);
3929 h.
setKeyValue(
"bytes_recv", tp_bytes_recv + s.tp_bytes_sent, 0);
3930 h.
setKeyValue(
"us_sent", tp_us_sent + s.tp_us_sent, 0);
3931 h.
setKeyValue(
"us_recv", tp_us_recv + s.tp_us_recv, 0);
3954 DLLLOCAL
void clearStats() {
3961 DLLLOCAL
void doTimeoutWarning(
const char* op,
int64 dt) {
3963 assert(dt > tl_warning_us);
3971 if (warn_callback_arg)
3974 warn_queue->pushAndTakeRef(h);
3977 DLLLOCAL
void doThroughputWarning(
bool send,
int64 bytes,
int64 dt,
double bs) {
3979 assert(bs < tp_warning_bs);
3989 if (warn_callback_arg)
3992 warn_queue->pushAndTakeRef(h);
3995 DLLLOCAL
bool pendingHttpChunkedBody()
const {
3996 return http_exp_chunked_body && sock != QORE_INVALID_SOCKET;
3999 DLLLOCAL
void setSslVerifyMode(
int mode) {
4001 ssl_verify_mode = mode;
4003 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
4006 DLLLOCAL
void acceptAllCertificates(
bool accept_all =
true) {
4007 ssl_accept_all_certs = accept_all;
4009 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
4014 ssl_err_str->
concat(
"; ");
4015 ssl_err_str->
concat(err_str);
4018 ssl_err_str = err_str;
4023 sock.priv->getUsageInfo(h, *s.priv);
4026 DLLLOCAL
static qore_socket_private* get(
QoreSocket& sock) {
4030 DLLLOCAL
static const qore_socket_private* get(
const QoreSocket& sock) {
4034 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 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:606
For use on the stack only: iterates through elements of a const QoreListNode.
Definition QoreListNode.h:575
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 const char * getTypeName() const
returns a string type description of the value contained (ex: "nothing" for a null AbstractQoreNode p...
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 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
base class for resolved call references
Definition CallReferenceNode.h:115
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:85
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:266
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