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];
527 typedef std::set<std::string> strset_t;
528 strset_t utf8_content_type_set = {
529 "application/ecmascript",
531 "application/x-javascript",
532 "application/javascript",
534 "application/ld+json",
536 "application/x-yaml",
544 int64 tl_warning_us = 0;
545 double tp_warning_bs = 0;
546 int64 tp_bytes_sent = 0,
558 http_exp_chunked_body =
false,
559 ssl_accept_all_certs =
false,
560 ssl_capture_remote_cert =
false,
564 ssl_verify_mode = SSL_VERIFY_NONE;
572 DLLLOCAL qore_socket_private(
int n_sock = QORE_INVALID_SOCKET,
int n_sfamily = AF_UNSPEC,
574 sock(n_sock), sfamily(n_sfamily), port(-1), stype(n_stype), sprot(n_prot), enc(n_enc) {
577 DLLLOCAL ~qore_socket_private() {
581 assert(!event_queue);
585 DLLLOCAL
bool isOpen() {
586 return sock != QORE_INVALID_SOCKET;
589 DLLLOCAL
int close() {
590 return close_internal();
593 DLLLOCAL
int close_and_reset() {
594 assert(sock != QORE_INVALID_SOCKET);
598 rc = ::closesocket(sock);
603 if (!rc || sock_get_error() != EINTR)
607 sock = QORE_INVALID_SOCKET;
623 if (http_exp_chunked_body) {
624 http_exp_chunked_body =
false;
633 client_target.clear();
637 DLLLOCAL
int close_internal() {
640 ssl_err_str->deref();
641 ssl_err_str =
nullptr;
644 remote_cert->
deref(
nullptr);
645 remote_cert =
nullptr;
655 if (!socketname.empty()) {
657 unlink(socketname.c_str());
665 return close_and_reset();
671 DLLLOCAL
void setAssumedEncoding(
const char* str) {
672 assume_http_encoding = str;
675 DLLLOCAL
const char* getAssumedEncoding()
const {
676 return assume_http_encoding.c_str();
679 DLLLOCAL
int getSendTimeout()
const {
682#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
685 int size =
sizeof(
hashdecl timeval);
687 socklen_t size =
sizeof(
hashdecl timeval);
690 if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
693 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
696 DLLLOCAL
int getRecvTimeout()
const {
699#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
702 int size =
sizeof(
hashdecl timeval);
704 socklen_t size =
sizeof(
hashdecl timeval);
707 if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (GETSOCKOPT_ARG_4)&tv, (socklen_t *)&size))
710 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
713 DLLLOCAL
int getPort() {
715 if (sock == QORE_INVALID_SOCKET || (sfamily != AF_INET && sfamily != AF_INET6) || port > 0)
719 hashdecl sockaddr_storage addr;
720#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
722 int size =
sizeof addr;
724 socklen_t size =
sizeof addr;
727 if (getsockname(sock, (
struct sockaddr *)&addr, (socklen_t *)&size) < 0)
730 port = q_get_port_from_addr((
const struct sockaddr *)&addr);
744 size_t offset = hdr.
size();
749 q_fix_decimal(&hdr, offset);
766 DLLLOCAL
static void do_headers(
QoreString& hdr,
const QoreHashNode* headers,
size_t size,
bool addsize =
true) {
774 const char* key = hi.getKey();
775 if (!size && addsize) {
776 if (!strcasecmp(key,
"transfer-encoding")) {
778 }
else if (!strcasecmp(key,
"content-type")
784 if ((addsize || size) && !strcasecmp(key,
"content-length")) {
791 do_header(key, hdr, li.getValue());
793 do_header(key, hdr, v);
797 if (size || addsize) {
798 hdr.
sprintf(
"Content-Length: %zu\r\n", size);
805 DLLLOCAL
int listen(
int backlog = 20) {
806 if (sock == QORE_INVALID_SOCKET)
811 if (::listen(sock, backlog)) {
818 return ::listen(sock, backlog);
822 DLLLOCAL
int accept_intern(
ExceptionSink* xsink,
struct sockaddr *addr, socklen_t *size,
int timeout_ms = -1) {
826 if (timeout_ms >= 0 && !isDataAvailable(timeout_ms,
"accept", xsink)) {
833 int rc = ::accept(sock, addr, size);
834 if (rc != QORE_INVALID_SOCKET)
838 if (sock_get_error() == EINTR)
841 qore_socket_error(xsink,
"SOCKET-ACCEPT-ERROR",
"error in accept()", 0, 0, 0, addr);
849 if (sock == QORE_INVALID_SOCKET) {
850 xsink->
raiseException(
"SOCKET-NOT-OPEN",
"socket must be opened, bound, and in a listening state before "
851 "new connections can be accepted");
856 se_in_op(
"Socket",
"accept", xsink);
859 se_in_op_thread(
"Socket",
"accept", xsink);
860 return QSE_IN_OP_THREAD;
864 if (sfamily == AF_UNIX) {
866 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"UNIX sockets are not available under Windows");
869 hashdecl sockaddr_un addr_un;
871#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
874 int size =
sizeof(
hashdecl sockaddr_un);
876 socklen_t size =
sizeof(
hashdecl sockaddr_un);
878 rc = accept_intern(xsink, (
struct sockaddr *)&addr_un, (socklen_t *)&size, timeout_ms);
881 if (rc >= 0 && source) {
883 addr->
sprintf(
"UNIX socket: %s", socketname.c_str());
884 source->priv->setAddress(addr);
885 source->priv->setHostName(
"localhost");
888 }
else if (sfamily == AF_INET || sfamily == AF_INET6) {
889 hashdecl sockaddr_storage addr_in;
890#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
893 int size =
sizeof(addr_in);
895 socklen_t size =
sizeof(addr_in);
898 rc = accept_intern(xsink, (
struct sockaddr *)&addr_in, (socklen_t *)&size, timeout_ms);
901 if (rc >= 0 && source) {
902 char host[NI_MAXHOST + 1];
903 char service[NI_MAXSERV + 1];
905 if (!getnameinfo((
struct sockaddr *)&addr_in, qore_get_in_len((
struct sockaddr *)&addr_in), host,
906 sizeof(host), service,
sizeof(service), NI_NUMERICSERV)) {
907 source->priv->setHostName(host);
911 char ifname[INET6_ADDRSTRLEN];
912 if (inet_ntop(addr_in.ss_family, qore_get_in_addr((
struct sockaddr *)&addr_in), ifname,
915 source->priv->setAddress(ifname);
920 xsink->
raiseException(
"SOCKET-ACCEPT-ERROR",
"do not know how to accept connections with address "
921 "family %d", sfamily);
927 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_SOCKET)
const {
946 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
949 event_queue->deref(xsink);
950 event_queue =
nullptr;
953 warn_queue->deref(xsink);
954 warn_queue =
nullptr;
955 if (warn_callback_arg) {
956 warn_callback_arg.
discard(xsink);
957 warn_callback_arg.
clear();
967 event_queue->deref(xsink);
971 event_data = with_data;
974 DLLLOCAL
void do_start_ssl_event() {
976 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_START_SSL));
980 DLLLOCAL
void do_ssl_established_event() {
985 event_queue->pushAndTakeRef(h);
989 DLLLOCAL
void do_connect_event(
int af,
const struct sockaddr* addr,
const char* target,
990 const char* service =
nullptr,
int prt = -1) {
999 q_af_to_hash(af, *h,
nullptr);
1005 event_queue->pushAndTakeRef(h);
1009 DLLLOCAL
void do_connected_event() {
1011 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CONNECTED));
1015 DLLLOCAL
void do_data_event_intern(
int event,
int source,
const QoreStringNode& str)
const {
1016 assert(event_queue && event_data && str.
size());
1019 event_queue->pushAndTakeRef(h.release());
1022 DLLLOCAL
void do_data_event(
int event,
int source,
const QoreStringNode& str)
const {
1023 if (event_queue && event_data && str.
size()) {
1024 do_data_event_intern(event, source, str);
1028 DLLLOCAL
void do_data_event(
int event,
int source,
const BinaryNode& b)
const {
1029 if (event_queue && event_data && b.
size()) {
1032 event_queue->pushAndTakeRef(h.release());
1036 DLLLOCAL
void do_data_event(
int event,
int source,
const void* data,
size_t size)
const {
1037 if (event_queue && event_data && size) {
1042 event_queue->pushAndTakeRef(h.release());
1046 DLLLOCAL
void do_header_event(
int event,
int source,
const QoreHashNode& hdr)
const {
1047 if (event_queue && event_data && !hdr.
empty()) {
1050 event_queue->pushAndTakeRef(h.release());
1054 DLLLOCAL
void do_chunked_read(
int event,
size_t bytes,
size_t total_read,
int source) {
1057 if (event == QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED)
1061 h->
setKeyValue(
"total_read", total_read,
nullptr);
1062 event_queue->pushAndTakeRef(h);
1066 DLLLOCAL
void do_read_http_header(
int event,
const QoreHashNode* headers,
int source) {
1070 event_queue->pushAndTakeRef(h);
1074 DLLLOCAL
void do_send_http_message_event(
const QoreString& str,
const QoreHashNode* headers,
int source) {
1076 QoreHashNode* h = getEvent(QORE_EVENT_HTTP_SEND_MESSAGE, source);
1080 event_queue->pushAndTakeRef(h);
1084 DLLLOCAL
void do_close_event() {
1086 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
1090 DLLLOCAL
void do_read_event(
size_t bytes_read,
size_t total_read,
size_t bufsize = 0,
int source = QORE_SOURCE_SOCKET) {
1093 QoreHashNode* h = getEvent(QORE_EVENT_PACKET_READ, source);
1095 h->
setKeyValue(
"total_read", total_read,
nullptr);
1098 h->
setKeyValue(
"total_to_read", bufsize,
nullptr);
1099 event_queue->pushAndTakeRef(h);
1103 DLLLOCAL
void do_send_event(
int bytes_sent,
int total_sent,
int bufsize) {
1108 h->
setKeyValue(
"total_sent", total_sent,
nullptr);
1109 h->
setKeyValue(
"total_to_send", bufsize,
nullptr);
1110 event_queue->pushAndTakeRef(h);
1114 DLLLOCAL
void do_resolve_event(
const char* host,
const char* service = 0) {
1117 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_LOOKUP);
1122 event_queue->pushAndTakeRef(h);
1126 DLLLOCAL
void do_resolved_event(
const struct sockaddr* addr) {
1129 QoreHashNode* h = getEvent(QORE_EVENT_HOSTNAME_RESOLVED);
1135 int prt = q_get_port_from_addr(addr);
1138 q_af_to_hash(addr->sa_family, *h,
nullptr);
1139 event_queue->pushAndTakeRef(h);
1143 DLLLOCAL
int64 getObjectIDForEvents()
const {
1147 DLLLOCAL
int connectUNIX(
const char* p,
int sock_type,
int protocol,
ExceptionSink* xsink) {
1150 QORE_TRACE(
"connectUNIX()");
1153 xsink->
raiseException(
"SOCKET-CONNECTUNIX-ERROR",
"UNIX sockets are not available under Windows");
1159 printd(5,
"qore_socket_private::connectUNIX(%s)\n", p);
1161 hashdecl sockaddr_un addr;
1163 addr.sun_family = AF_UNIX;
1165 strncpy(addr.sun_path, p,
sizeof(addr.sun_path) - 1);
1166 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1167 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_SOCKET_ERROR) {
1168 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"error connecting to UNIX socket: '%s'", p);
1172 do_connect_event(AF_UNIX, (sockaddr*)&addr, p);
1174 if (!::connect(sock, (
const sockaddr *)&addr,
sizeof(
struct sockaddr_un)))
1178 if (sock_get_error() == EINTR)
1184 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, p);
1190 socketname = addr.sun_path;
1193 do_connected_event();
1205 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
const char* cname,
const char* mname,
1208 assert(read || write);
1209 if (sock == QORE_INVALID_SOCKET) {
1210 se_not_open(cname, mname, xsink,
"asyncIoWait");
1214 return asyncIoWait(timeout_ms, read, write, xsink);
1217 DLLLOCAL
int asyncIoWait(
int timeout_ms,
bool read,
bool write,
ExceptionSink* xsink)
const {
1219#if defined HAVE_POLL
1220 return poll_intern(xsink, timeout_ms, read, write);
1221#elif defined HAVE_SELECT
1222 return select_intern(xsink, timeout_ms, read, write);
1224#error no async socket operations supported
1228#if defined HAVE_POLL
1229 DLLLOCAL
int poll_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1236 pollfd fds = {sock, arg, 0};
1238 rc = ::poll(&fds, 1, timeout_ms);
1239 if (rc == -1 && errno == EINTR)
1244 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"poll(2) returned an error");
1245 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
1250#elif defined HAVE_SELECT
1251 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write)
const {
1252 bool aborted =
false;
1253 int rc = select_intern(xsink, timeout_ms, read, write, aborted);
1254 if (rc != QORE_SOCKET_ERROR && aborted)
1259 DLLLOCAL
int select_intern(
ExceptionSink* xsink,
int timeout_ms,
bool read,
bool write,
bool& aborted)
const {
1266 if (sock >= FD_SETSIZE) {
1267 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);
1271 hashdecl timeval tv;
1282 tv.tv_sec = timeout_ms / 1000;
1283 tv.tv_usec = (timeout_ms % 1000) * 1000;
1285 fd_set* readfd = read ? &sfs : 0;
1286 fd_set* writefd = write ? &sfs : 0;
1288 rc = select(sock + 1, readfd, writefd, &err, &tv);
1290 if (rc != QORE_SOCKET_ERROR) {
1291 if (FD_ISSET(sock, &err))
1295 if (sock_get_error() != EINTR)
1298 if (rc == QORE_SOCKET_ERROR) {
1301 qore_socket_error(xsink,
"SOCKET-SELECT-ERROR",
"select(2) returned an error");
1308 DLLLOCAL
bool tryReadSocketData(
const char* mname,
ExceptionSink* xsink) {
1313 return asyncIoWait(0,
true,
false,
"Socket", mname, xsink);
1317 int rc = ssl->doSSLRW(xsink, mname, rbuf, 1, 0, PEEK,
false);
1318 if (*xsink || (rc == QSE_TIMEOUT)) {
1321 return rc > 0 ? true :
false;
1324 DLLLOCAL
bool isSocketDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1325 return asyncIoWait(timeout_ms,
true,
false,
"Socket", mname, xsink);
1328 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1331 return isSocketDataAvailable(timeout_ms, mname, xsink);
1334 DLLLOCAL
bool isWriteFinished(
int timeout_ms,
const char* mname,
ExceptionSink* xsink) {
1335 return asyncIoWait(timeout_ms,
false,
true,
"Socket", mname, xsink);
1338 DLLLOCAL
int close_and_exit() {
1339 if (sock != QORE_INVALID_SOCKET)
1344 DLLLOCAL
int connectINETTimeout(
int timeout_ms,
const struct sockaddr* ai_addr,
size_t ai_addrlen,
1347 PrivateQoreSocketTimeoutHelper toh(
this,
"connect");
1350 if (!::connect(sock, ai_addr, ai_addrlen))
1354 if (sock_get_error() != EAGAIN) {
1355 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1363 if (errno != EINPROGRESS)
1372 bool aborted =
false;
1373 int rc = select_intern(xsink, timeout_ms,
false,
true, aborted);
1380 if (rc != QORE_SOCKET_ERROR && aborted) {
1381 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, 0, 0, ai_addr);
1385 int rc = asyncIoWait(timeout_ms,
false,
true,
"Socket",
"connectINETTimeout", xsink);
1391 if (rc == QORE_SOCKET_ERROR && sock_get_error() != EINTR) {
1393 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in asyncIoWait() with "
1394 "Socket::connect() with timeout", 0, 0, 0, ai_addr);
1396 }
else if (rc > 0) {
1397 return checkConnected(xsink,
nullptr, ai_addr, only_timeout);
1401 concat_target(*(*desc), ai_addr);
1411 DLLLOCAL
int checkConnected(
ExceptionSink* xsink,
const char* hostsvc,
const struct sockaddr* ai_addr =
nullptr,
1412 bool only_timeout =
false) {
1416 socklen_t lon =
sizeof(int);
1419 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (GETSOCKOPT_ARG_4)(&val), &lon) == QORE_SOCKET_ERROR) {
1420 if (!only_timeout) {
1421 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
nullptr,
1432 qore_socket_error_intern(val, xsink,
"SOCKET-CONNECT-ERROR",
"error in getsockopt()",
nullptr, hostsvc,
1441 DLLLOCAL
void confirmConnected(
const char* host) {
1442 do_connected_event();
1446 client_target = host;
1450 DLLLOCAL
int sock_errno_err(
const char* err,
const char* desc,
ExceptionSink* xsink) {
1452 qore_socket_error(xsink, err, desc);
1456 DLLLOCAL
int set_non_blocking(
bool non_blocking,
ExceptionSink* xsink) {
1459 if (sock == QORE_INVALID_SOCKET) {
1465 u_long mode = non_blocking ? 1 : 0;
1466 int rc = ioctlsocket(sock, FIONBIO, &mode);
1467 if (check_windows_rc(rc)) {
1468 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in ioctlsocket(FIONBIO)", xsink);
1474 if ((arg = fcntl(sock, F_GETFL, 0)) < 0) {
1475 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() getting socket descriptor status "
1485 if (fcntl(sock, F_SETFL, arg) < 0) {
1486 return sock_errno_err(
"SOCKET-CONNECT-ERROR",
"error in fcntl() setting socket descriptor status "
1495 DLLLOCAL
int connectINET(
const char* host,
const char* service,
int timeout_ms,
ExceptionSink* xsink,
1496 int family = AF_UNSPEC,
int type = SOCK_STREAM,
int protocol = 0) {
1498 family = q_get_af(family);
1499 type = q_get_sock_type(type);
1501 QORE_TRACE(
"qore_socket_private::connectINET()");
1506 printd(5,
"qore_socket_private::connectINET(%s:%s, %dms)\n", host, service, timeout_ms);
1508 do_resolve_event(host, service);
1511 if (ai.
getInfo(xsink, host, service, family, 0, type, protocol))
1518 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1519 do_resolved_event(p->ai_addr);
1521 int prt = q_get_port_from_addr(aip->ai_addr);
1523 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1524 if (!connectINETIntern(host, service, p->ai_family, p->ai_addr, p->ai_addrlen, p->ai_socktype,
1525 p->ai_protocol, prt, timeout_ms, xsink,
true)) {
1534 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1539 DLLLOCAL
int connectINETIntern(
const char* host,
const char* service,
int ai_family,
struct sockaddr* ai_addr,
1540 size_t ai_addrlen,
int ai_socktype,
int ai_protocol,
int prt,
int timeout_ms,
ExceptionSink* xsink,
1541 bool only_timeout =
false) {
1543 printd(5,
"qore_socket_private::connectINETIntern() host: %s service: %s family: %d timeout_ms: %d\n", host,
1544 service, ai_family, timeout_ms);
1545 if ((sock = socket(ai_family, ai_socktype, ai_protocol)) == QORE_INVALID_SOCKET) {
1546 xsink->
raiseErrnoException(
"SOCKET-CONNECT-ERROR", errno,
"cannot establish a connection to %s:%s", host,
1557 if (timeout_ms >= 0) {
1559 if (set_non_blocking(
true, xsink))
1560 return close_and_exit();
1562 do_connect_event(ai_family, ai_addr, host, service, prt);
1564 rc = connectINETTimeout(timeout_ms, ai_addr, ai_addrlen, xsink, only_timeout);
1568 if (set_non_blocking(
false, xsink))
1569 return close_and_exit();
1571 do_connect_event(ai_family, ai_addr, host, service, prt);
1574 rc = ::connect(sock, ai_addr, ai_addrlen);
1577 if (!rc || sock_get_error() != EINTR)
1583 if (!only_timeout || errno == ETIMEDOUT)
1584 qore_socket_error(xsink,
"SOCKET-CONNECT-ERROR",
"error in connect()", 0, host, service);
1586 return close_and_exit();
1589 sfamily = ai_family;
1590 stype = ai_socktype;
1591 sprot = ai_protocol;
1596 confirmConnected(host);
1600 DLLLOCAL
int upgradeClientToSSLIntern(
ExceptionSink* xsink,
const char* mname,
const char* sni_target_host,
1603 SSLSocketHelperHelper sshh(
this,
true);
1606 do_start_ssl_event();
1608 if (!sni_target_host && !client_target.empty()) {
1609 sni_target_host = client_target.c_str();
1611 if ((rc = ssl->setClient(xsink, mname, sni_target_host, sock, cert, pkey))
1612 || ssl->connect(mname, timeout_ms,
1615 return rc ? rc : -1;
1617 do_ssl_established_event();
1622 DLLLOCAL
int upgradeServerToSSLIntern(
ExceptionSink* xsink,
const char* mname,
int timeout_ms,
1626 SSLSocketHelperHelper sshh(
this,
true);
1628 do_start_ssl_event();
1629 if (ssl->setServer(xsink, mname, sock, cert, pkey) || ssl->accept(mname, timeout_ms, xsink)) {
1633 do_ssl_established_event();
1639 DLLLOCAL
int openUNIX(
int sock_type = SOCK_STREAM,
int protocol = 0) {
1640 if (sock != QORE_INVALID_SOCKET)
1643 if ((sock = socket(AF_UNIX, sock_type, protocol)) == QORE_INVALID_SOCKET) {
1655 DLLLOCAL
int openINET(
int family = AF_INET,
int sock_type = SOCK_STREAM,
int protocol = 0) {
1656 if (sock != QORE_INVALID_SOCKET)
1659 if ((sock = socket(family, sock_type, protocol)) == QORE_INVALID_SOCKET)
1669 DLLLOCAL
int reuse(
int opt) {
1671 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_ARG_4)&opt,
sizeof(
int));
1675 DLLLOCAL
int bindIntern(
struct sockaddr* ai_addr,
size_t ai_addrlen,
int prt,
bool reuseaddr,
ExceptionSink* xsink = 0) {
1678 if ((::bind(sock, ai_addr, ai_addrlen)) == QORE_SOCKET_ERROR) {
1680 qore_socket_error(xsink,
"SOCKET-BIND-ERROR",
"error in bind()", 0, 0, 0, ai_addr);
1690#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1692 int len = ai_addrlen;
1694 socklen_t len = ai_addrlen;
1697 if (getsockname(sock, ai_addr, &len))
1700 port = q_get_port_from_addr(ai_addr);
1706 DLLLOCAL
int bindUNIX(
ExceptionSink* xsink,
const char* name,
int socktype = SOCK_STREAM,
int protocol = 0) {
1709 xsink->
raiseException(
"SOCKET-BINDUNIX-ERROR",
"UNIX sockets are not available under Windows");
1715 if (openUNIX(socktype, protocol)) {
1716 xsink->
raiseErrnoException(
"SOCKET-BIND-ERROR", errno,
"error opening UNIX socket ('%s') for bind", name);
1720 hashdecl sockaddr_un addr;
1721 addr.sun_family = AF_UNIX;
1723 strncpy(addr.sun_path, name,
sizeof(addr.sun_path) - 1);
1724 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
1726 if (bindIntern((sockaddr*)&addr,
sizeof(
struct sockaddr_un), -1,
false, xsink))
1730 socketname = addr.sun_path;
1737 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) {
1739 family = q_get_af(family);
1740 socktype = q_get_sock_type(socktype);
1745 do_resolve_event(name, service);
1746 if (ai.
getInfo(xsink, name, service, family, AI_PASSIVE, socktype, protocol))
1752 for (
struct addrinfo* p = aip; p; p = p->ai_next)
1753 do_resolved_event(p->ai_addr);
1756 if (openINET(aip->ai_family, aip->ai_socktype, protocol)) {
1757 qore_socket_error(xsink,
"SOCKET-BINDINET-ERROR",
"error opening socket for bind", 0, name, service);
1761 int prt = q_get_port_from_addr(aip->ai_addr);
1765 for (
struct addrinfo* p = aip; p; p = p->ai_next) {
1766 if (!bindIntern(p->ai_addr, p->ai_addrlen, prt, reuseaddr)) {
1771 en = sock_get_raw_error();
1776 qore_socket_error_intern(en, xsink,
"SOCKET-BIND-ERROR",
"error binding on socket", 0, name, service);
1783 if (sock == QORE_INVALID_SOCKET) {
1784 se_not_open(
"Socket",
"getPeerInfo", xsink);
1788 hashdecl sockaddr_storage addr;
1789 socklen_t len =
sizeof addr;
1790 if (getpeername(sock, (
struct sockaddr*)&addr, &len)) {
1791 qore_socket_error(xsink,
"SOCKET-GETPEERINFO-ERROR",
"error in getpeername()");
1795 return getAddrInfo(addr, len, host_lookup);
1801 if (sock == QORE_INVALID_SOCKET) {
1802 se_not_open(
"Socket",
"getSocketInfo", xsink);
1806 hashdecl sockaddr_storage addr;
1807#if defined(HPUX) && defined(__ia64) && defined(__LP64__)
1809 int len =
sizeof addr;
1811 socklen_t len =
sizeof addr;
1814 if (getsockname(sock, (
struct sockaddr*)&addr, &len)) {
1815 qore_socket_error(xsink,
"SOCKET-GETSOCKETINFO-ERROR",
"error in getsockname()");
1819 return getAddrInfo(addr, len, host_lookup);
1822 DLLLOCAL
QoreHashNode* getAddrInfo(
const struct sockaddr_storage& addr, socklen_t len,
bool host_lookup =
true)
const {
1825 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1827 char host[NI_MAXHOST + 1];
1829 if (!getnameinfo((
struct sockaddr*)&addr, qore_get_in_len((
struct sockaddr*)&addr), host,
sizeof(host), 0, 0, 0)) {
1837 char ifname[INET6_ADDRSTRLEN];
1838 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr*)&addr), ifname,
sizeof(ifname))) {
1845 if (addr.ss_family == AF_INET) {
1846 hashdecl sockaddr_in* s = (
hashdecl sockaddr_in*)&addr;
1847 tport = ntohs(s->sin_port);
1849 hashdecl sockaddr_in6* s = (
hashdecl sockaddr_in6*)&addr;
1850 tport = ntohs(s->sin6_port);
1856 else if (addr.ss_family == AF_UNIX) {
1857 assert(!socketname.empty());
1873 hashdecl sockaddr_storage addr;
1875 socklen_t len =
sizeof addr;
1876 if (getpeername(sock, (
struct sockaddr*)&addr, &len))
1879 if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
1881 char ifname[INET6_ADDRSTRLEN];
1882 if (inet_ntop(addr.ss_family, qore_get_in_addr((
struct sockaddr *)&addr), ifname,
sizeof(ifname))) {
1887 char host[NI_MAXHOST + 1];
1888 if (!getnameinfo((
struct sockaddr *)&addr, qore_get_in_len((
struct sockaddr *)&addr), host,
sizeof(host),
1894 else if (addr.ss_family == AF_UNIX) {
1896 hashdecl sockaddr_un *addr_un = (
hashdecl sockaddr_un *)&addr;
1897 astr->
sprintf(
"UNIX socket: %s", addr_un->sun_path);
1910 DLLLOCAL
int readByteFromBuffer(
char& output) {
1912 assert(sock != QORE_INVALID_SOCKET);
1919 output = *(rbuf + bufoffset);
1931 DLLLOCAL ssize_t brecv(
ExceptionSink* xsink,
const char* meth,
char*& buf,
size_t bs,
int flags,
1932 int timeout,
bool do_event =
true,
bool suppress_exception =
false) {
1935 assert(sock != QORE_INVALID_SOCKET);
1940 buf = rbuf + bufoffset;
1959 if (timeout >= 0 && !isDataAvailable(timeout, meth, xsink)) {
1963 if (!suppress_exception) {
1964 se_timeout(
"Socket", meth, timeout, xsink);
1971 rc = ::recv(sock, rbuf, DEFAULT_SOCKET_BUFSIZE, flags);
1972 if (rc == QORE_SOCKET_ERROR) {
1974 if (errno == EINTR) {
1978 if (errno == ECONNRESET) {
1979 if (!suppress_exception) {
1980 se_closed(
"Socket", meth, xsink);
1985 if (!suppress_exception) {
1986 qore_socket_error(xsink,
"SOCKET-RECV-ERROR",
"error in recv()", meth);
1998 rc = ssl->read(xsink, meth, rbuf, DEFAULT_SOCKET_BUFSIZE, timeout, suppress_exception);
2006 if (rc > (ssize_t)bs) {
2014 do_read_event(rc, rc);
2018 if (!rc && isOpen() && errno != EAGAIN && errno != EINPROGRESS) {
2028 bool exit_early =
false) {
2031 if (sock == QORE_INVALID_SOCKET) {
2032 se_not_open(
"Socket", meth, xsink,
"readHTTPData");
2037 PrivateQoreSocketThroughputHelper th(
this,
false);
2052 rc = brecv(xsink, meth, buf, 1, 0, timeout,
false);
2063 se_closed(
"Socket", meth, xsink);
2065 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"socket closed on remote end "
2066 "while reading header data after reading " QSD
" byte%s", count, count == 1 ?
"" :
"s");
2072 if (++count == QORE_MAX_HEADER_SIZE) {
2073 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"header size cannot exceed " QSD
" bytes", count);
2084 if (exit_early && hdr->
empty())
2091 }
else if (c ==
'\r') {
2106 case 0: hdr->concat(
'\r');
break;
2107 case 1: hdr->concat(
"\r\n");
break;
2108 case 2: hdr->concat(
"\r\n\r");
break;
2109 case 3: hdr->concat(
'\n');
break;
2118 th.finalize(hdr->
size());
2119 return hdr.release();
2123 int source = QORE_SOURCE_SOCKET) {
2125 if (sock == QORE_INVALID_SOCKET) {
2126 se_not_open(
"Socket",
"recv", xsink,
"recv");
2132 se_in_op(
"Socket",
"recv", xsink);
2135 se_in_op_thread(
"Socket",
"recv", xsink);
2139 PrivateQoreSocketThroughputHelper th(
this,
false);
2141 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2148 rc = brecv(xsink,
"recv", buf, bs, 0, timeout,
false);
2154 printd(5,
"qore_socket_private::recv(" QSD
", %d) bs=" QSD
", br=" QSD
", rc=" QSD
", errno: %d "
2155 "(%s)\n", bufsize, timeout, bs, str->
size(), rc, errno, strerror(errno));
2163 do_read_event(rc, str->
size(), bufsize, source);
2167 if (str->
size() >= (
size_t)bufsize)
2169 if ((bufsize - str->
size()) < bs)
2170 bs = bufsize - str->
size();
2174 printd(5,
"qore_socket_private::recv() received " QSD
" byte(s), bufsize=" QSD
", strlen=" QSD
" str='%s'\n",
2175 str->
size(), bufsize, (str ? str->
strlen() : 0), str ? str->c_str() :
"n/a");
2181 th.finalize(str->
size());
2188 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2190 return str.release();
2194 int source = QORE_SOURCE_SOCKET) {
2196 if (sock == QORE_INVALID_SOCKET) {
2197 se_not_open(
"Socket",
"recv", xsink,
"recvAll");
2203 se_in_op(
"Socket",
"recv", xsink);
2206 se_in_op_thread(
"Socket",
"recv", xsink);
2210 PrivateQoreSocketThroughputHelper th(
this,
false);
2216 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2225 do_read_event(rc, rc);
2228 if (isDataAvailable(0,
"recv", xsink)) {
2230 rc = brecv(xsink,
"recv", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false,
true);
2239 do_read_event(rc, str->
size());
2240 }
while (isDataAvailable(0,
"recv", xsink));
2243 th.finalize(str->
size());
2251 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **str);
2253 return str.release();
2256 DLLLOCAL
int recv(
int fd, ssize_t size,
int timeout_ms,
ExceptionSink* xsink);
2259 int source = QORE_SOURCE_SOCKET) {
2261 if (sock == QORE_INVALID_SOCKET) {
2262 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinary");
2268 se_in_op(
"Socket",
"recvBinary", xsink);
2271 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2275 PrivateQoreSocketThroughputHelper th(
this,
false);
2277 size_t bs = bufsize > 0 && bufsize < DEFAULT_SOCKET_BUFSIZE ? bufsize : DEFAULT_SOCKET_BUFSIZE;
2283 rc = brecv(xsink,
"recvBinary", buf, bs, 0, timeout);
2290 if (b->
size() >= (
size_t)bufsize)
2292 if ((bufsize - b->
size()) < bs)
2293 bs = bufsize - b->
size();
2297 th.finalize(b->
size());
2307 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2309 printd(5,
"qore_socket_private::recvBinary() received " QSD
" byte(s), bufsize=" QSD
", blen=" QSD
"\n",
2315 int source = QORE_SOURCE_SOCKET) {
2317 if (sock == QORE_INVALID_SOCKET) {
2318 se_not_open(
"Socket",
"recvBinary", xsink,
"recvBinaryAll");
2324 se_in_op(
"Socket",
"recvBinary", xsink);
2327 se_in_op_thread(
"Socket",
"recvBinary", xsink);
2331 PrivateQoreSocketThroughputHelper th(
this,
false);
2338 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, timeout,
false);
2347 do_read_event(rc, rc);
2350 while (isDataAvailable(0,
"recvBinary", xsink)) {
2351 rc = brecv(xsink,
"recvBinary", buf, DEFAULT_SOCKET_BUFSIZE, 0, 0,
false,
true);
2361 do_read_event(rc, b->
size());
2364 th.finalize(b->
size());
2371 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, **b);
2380 if (sock == QORE_INVALID_SOCKET) {
2381 se_not_open(
"Socket",
"recvToOutputStream", xsink);
2386 se_in_op(
"Socket",
"recvToOutputStream", xsink);
2389 se_in_op_thread(
"Socket",
"recvToOutputStream", xsink);
2393 qore_socket_op_helper oh(
this);
2397 while (size < 0 || br < size) {
2399 int bn = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - br, DEFAULT_SOCKET_BUFSIZE);
2401 ssize_t rc = brecv(xsink,
"recvToOutputStream", buf, bn, 0, timeout);
2410 xsink->
raiseException(
"SOCKET-RECV-ERROR",
"Unexpected end of stream");
2416 do_data_event(QORE_EVENT_SOCKET_DATA_READ, source, buf, rc);
2422 os->
write(buf, rc, xsink);
2441 do_data_event(QORE_EVENT_HTTP_HEADERS_READ, source, **hdr);
2442 return hdr.release();
2446 ssize_t& rc,
int source,
const char* headers_raw_key =
"headers-raw") {
2455 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"remote closed the connection while reading the HTTP header");
2460 return processHttpHeaderString(xsink, hdr, info, source, headers_raw_key);
2465 QoreHashNode* info,
int source,
const char* headers_raw_key =
"headers-raw") {
2466 const char* buf = hdr->
c_str();
2468 if ((p = (
char*)strstr(buf,
"\r\n"))) {
2471 }
else if ((p = (
char*)strchr(buf,
'\n'))) {
2474 }
else if ((p = (
char*)strchr(buf,
'\r'))) {
2480 xsink->
raiseException(
"SOCKET-HTTP-ERROR",
"invalid header received with embedded nulls in "
2481 "Socket::readHTTPHeader()");
2486 if (!(t1 = (
char*)strstr(buf,
"HTTP/"))) {
2487 xsink->
raiseExceptionArg(
"SOCKET-HTTP-ERROR", hdr.release(),
"missing HTTP version string in "
2488 "first header line in Socket::readHTTPHeader()");
2495 int flags = CHF_PROCESS;
2502 flags |= CHF_HTTP11;
2508 const char* info_key;
2510 char* t2 = (
char*)strchr(buf + 8,
' ');
2513 if (isdigit(*(t2))) {
2515 if (strlen(t2) > 4) {
2522 info_key =
"response-uri";
2524 char* t2 = (
char*)strchr(buf,
' ');
2529 t1 = strchr(t2,
' ');
2537 info_key =
"request-uri";
2538 flags |= CHF_REQUEST;
2542 if (info || (event_queue && event_data)) {
2544 if (info && event_queue && event_data) {
2547 if (event_queue && event_data) {
2548 do_data_event_intern(QORE_EVENT_SOCKET_DATA_READ, source, **status_line);
2551 info->
setKeyValue(info_key, *status_line,
nullptr);
2553 status_line.release();
2556 bool close = convertHeaderToHash(*h, p, flags, info, &http_exp_chunked_body, headers_raw_key);
2557 do_read_http_header(QORE_EVENT_HTTP_MESSAGE_RECEIVED, *h, source);
2560 if ((flags & CHF_REQUEST) && info) {
2568 DLLLOCAL
int runHeaderCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2570 bool send_aborted =
false,
QoreObject* obj =
nullptr) {
2579 arg->
setKeyValue(
"send_aborted", send_aborted, xsink);
2580 args->push(arg,
nullptr);
2583 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2586 DLLLOCAL
int runTrailerCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2589 if (runCallback(xsink, cname, mname, rv, callback, l,
nullptr))
2600 xsink->
raiseException(
"HTTP-TRAILER-ERROR",
"chunked callback returned type '%s'; expecting 'hash' "
2607 DLLLOCAL
int runDataCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2614 args->push(arg,
nullptr);
2617 return runCallback(xsink, cname, mname, rv, callback, l, *args);
2633 return *xsink ? -1 : 0;
2636 DLLLOCAL
int sendHttpChunkedWithCallback(
ExceptionSink* xsink,
const char* cname,
const char* mname,
2638 bool* aborted =
nullptr) {
2640 assert(!aborted || !(*aborted));
2642 if (sock == QORE_INVALID_SOCKET) {
2643 se_not_open(cname, mname, xsink,
"sendHttpChunkedWithCallback");
2644 return QSE_NOT_OPEN;
2648 se_in_op(cname, mname, xsink);
2651 se_in_op_thread(cname, mname, xsink);
2655 PrivateQoreSocketThroughputHelper th(
this,
true);
2658 bool nb = (timeout_ms >= 0);
2660 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2664 qore_socket_op_helper oh(
this);
2673 bool data_available = tryReadSocketData(mname, xsink);
2675 if (data_available || *xsink) {
2677 return *xsink ? -1 : 0;
2683 rc = runCallback(xsink, cname, mname, res, send_callback, &l);
2692 const char* data_ptr =
nullptr;
2693 size_t data_size = 0;
2695 switch (res->getType()) {
2703 data_ptr = str->
c_str();
2704 data_size = str->
size();
2716 data_ptr =
static_cast<const char*
>(b->
getPtr());
2717 data_size = b->
size();
2729 const char* key = hi.getKey();
2736 do_header(key, buf, li.getValue());
2738 do_header(key, buf, v);
2749 xsink->
raiseException(
"SOCKET-CALLBACK-ERROR",
"HTTP chunked data callback returned type '%s'; expecting one of: 'string', 'binary', 'hash', 'nothing' (or 'NULL')", res->getTypeName());
2755 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2761 if (data_ptr && data_size) {
2762 rc = sendIntern(xsink, cname, mname, data_ptr, data_size, timeout_ms, total,
true);
2767 if (buf.
empty() && (!data_ptr || !data_size)) {
2768 buf.
set(
"0\r\n\r\n");
2772 rc = sendIntern(xsink, cname, mname, buf.
c_str(), buf.
size(), timeout_ms, total,
true);
2778 switch (res->getType()) {
2781 if (!str->
empty()) {
2782 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *str);
2790 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, source, *b);
2797 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, source, *h);
2805 if (aborted && *xsink) {
2806 bool data_available = tryReadSocketData(mname, xsink);
2808 if (data_available) {
2810 return *xsink ? -1 : 0;
2819 if (rc < 0 || sock == QORE_INVALID_SOCKET)
2825 return rc < 0 || sock == QORE_INVALID_SOCKET ? -1 : 0;
2829 DLLLOCAL ssize_t sendIntern(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2830 int timeout_ms,
int64& total,
bool stream =
false) {
2836 bool nb = (timeout_ms >= 0);
2841 rc = ssl->write(mname, buf + bs, size - bs, timeout_ms, xsink);
2844 rc = ::send(sock, buf + bs, size - bs, 0);
2851 if (nb && (errno == EAGAIN
2853 || errno == EWOULDBLOCK
2856 if (!isWriteFinished(timeout_ms, mname, xsink)) {
2859 se_timeout(
"Socket", mname, timeout_ms, xsink);
2865 if (errno != EINTR) {
2867 xsink->
raiseErrnoException(
"SOCKET-SEND-ERROR", errno,
"error while executing %s::%s()", cname, mname);
2871 if (!stream && errno == EPIPE) {
2876 if (!stream && errno == ECONNRESET) {
2889 if (rc < 0 || sock == QORE_INVALID_SOCKET) {
2893 do_send_event(rc, bs, size);
2902 DLLLOCAL
int send(
int fd, ssize_t size,
int timeout_ms,
ExceptionSink* xsink);
2905 DLLLOCAL
int send(
ExceptionSink* xsink,
const char* cname,
const char* mname,
const char* buf,
size_t size,
2906 int timeout_ms = -1,
int source = QORE_SOURCE_SOCKET) {
2908 if (sock == QORE_INVALID_SOCKET) {
2909 se_not_open(cname, mname, xsink,
"send");
2910 return QSE_NOT_OPEN;
2914 se_in_op(cname, mname, xsink);
2917 se_in_op_thread(cname, mname, xsink);
2924 PrivateQoreSocketThroughputHelper th(
this,
true);
2927 bool nb = (timeout_ms >= 0);
2929 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2935 ssize_t rc = sendIntern(xsink, cname, mname, buf, size, timeout_ms, total);
2938 if (rc > 0 && source > 0) {
2939 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, buf, size);
2942 return rc < 0 || sock == QORE_INVALID_SOCKET ? rc : 0;
2947 if (sock == QORE_INVALID_SOCKET) {
2948 se_not_open(
"Socket",
"sendFromInputStream", xsink);
2953 se_in_op(
"Socket",
"sendFromInputStream", xsink);
2956 se_in_op_thread(
"Socket",
"sendFromInputStream", xsink);
2960 qore_socket_op_helper oh(
this);
2962 PrivateQoreSocketThroughputHelper th(
this,
true);
2965 bool nb = (timeout >= 0);
2967 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
2971 char buf[DEFAULT_SOCKET_BUFSIZE];
2974 while (size < 0 || sent < size) {
2975 int64 toRead = size < 0 ? DEFAULT_SOCKET_BUFSIZE :
QORE_MIN(size - sent, DEFAULT_SOCKET_BUFSIZE);
2979 r = is->
read(buf, toRead, xsink);
2988 xsink->
raiseException(
"SOCKET-SEND-ERROR",
"Unexpected end of stream");
2994 ssize_t rc = sendIntern(xsink,
"Socket",
"sendFromInputStream", buf, r, timeout, total);
2998 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, QORE_SOURCE_SOCKET, buf, r);
3005 if (sock == QORE_INVALID_SOCKET) {
3006 se_not_open(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
3011 se_in_op(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
3014 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyFromInputStream", xsink);
3018 qore_socket_op_helper oh(
this);
3020 PrivateQoreSocketThroughputHelper th(
this,
true);
3023 bool nb = (timeout >= 0);
3025 OptionalNonBlockingHelper onbh(*
this, !ssl && nb, xsink);
3031 buf->preallocate(max_chunk_size);
3037 r = is->
read((
void*)buf->getPtr(),
sizeof(max_chunk_size), xsink);
3044 str.
sprintf(
"%x\r\n", (
int)r);
3045 int rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
3049 bool trailers =
false;
3053 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", (
const char*)buf->getPtr(), r, timeout, total,
true);
3056 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_SENT, QORE_SOURCE_SOCKET, buf->getPtr(), r);
3057 }
else if (trailer_callback) {
3061 if (runTrailerCallback(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", *trailer_callback, l, h))
3065 do_headers(str, *h, 0,
false);
3067 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
3071 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, **h);
3079 rc = sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyFromInputStream", str.
c_str(), str.
size(), timeout, total,
true);
3093 if (sock == QORE_INVALID_SOCKET) {
3094 se_not_open(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3099 se_in_op(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3102 se_in_op_thread(
"Socket",
"sendHttpChunkedBodyTrailer", xsink);
3112 const char* key = hi.getKey();
3117 do_header(key, buf, li.getValue());
3120 do_header(key, buf, v);
3125 sendIntern(xsink,
"Socket",
"sendHttpChunkedBodyTrailer", buf.
c_str(), buf.
size(), timeout, total,
true);
3127 do_header_event(QORE_EVENT_HTTP_FOOTERS_SENT, QORE_SOURCE_SOCKET, *headers);
3131 DLLLOCAL
void getSendHttpMessageHeaders(
QoreString& hdr,
QoreHashNode* info,
const char* method,
const char* path,
3132 const char* http_version,
const QoreHashNode* headers,
size_t size,
int source) {
3134 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3141 getSendHttpMessageHeadersCommon(hdr, info, headers, size, source);
3145 size_t size,
int source) {
3147 do_send_http_message_event(hdr, headers, source);
3152 do_headers(hdr, headers, size);
3156 const char* method,
const char* path,
const char* http_version,
const QoreHashNode* headers,
3164 hdr.
sprintf(
"%s %s HTTP/%s", method, path && path[0] ? path :
"/", http_version);
3171 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3172 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3184 hdr.
sprintf(
"HTTP/%s %03d %s", http_version, code, desc);
3192 return sendHttpMessageCommon(xsink, hdr, info, cname, mname, headers, body, data, size, send_callback,
3193 input_stream, max_chunk_size, trailer_callback, source, timeout_ms, l, aborted);
3202 assert(!(data && send_callback));
3203 assert(!(data && input_stream));
3204 assert(!(send_callback && input_stream));
3207 do_send_http_message_event(hdr, headers, source);
3212 do_headers(hdr, headers, size && data ? size : 0);
3218 if ((rc = send(xsink, cname, mname, hdr.
c_str(), hdr.
size(), timeout_ms, -1)))
3223 int rc = send(xsink, cname, mname, (
char*)data, size, timeout_ms, -1);
3226 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, *body);
3228 do_data_event(QORE_EVENT_SOCKET_DATA_SENT, source, data, size);
3232 }
else if (send_callback) {
3234 assert(!aborted || !(*aborted));
3235 return sendHttpChunkedWithCallback(xsink, cname, mname, *send_callback, *l, source, timeout_ms, aborted);
3236 }
else if (input_stream) {
3238 sendHttpChunkedBodyFromInputStream(input_stream, max_chunk_size, timeout_ms, xsink, l, trailer_callback);
3239 return *xsink ? -1 : 0;
3250 if (sock == QORE_INVALID_SOCKET) {
3251 se_not_open(cname,
"readHTTPChunkedBodyBinary", xsink);
3256 se_in_op(cname,
"readHTTPChunkedBodyBinary", xsink);
3259 se_in_op_thread(cname,
"readHTTPChunkedBodyBinary", xsink);
3264 if (http_exp_chunked_body)
3265 http_exp_chunked_body =
false;
3267 qore_socket_op_helper oh(
this);
3280 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 1, 0, timeout,
false);
3284 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3291 if (!state && c ==
'\r')
3293 else if (state && c ==
'\n')
3308 char* p = (
char*)strchr(str.
c_str(),
';');
3311 long size = strtol(str.
c_str(), 0, 16);
3312 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
size(), source);
3319 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3326 ssize_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3330 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, bs, 0, timeout,
false);
3336 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3341 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, buf, (
size_t)rc);
3345 os->
write(buf, rc, xsink);
3356 if (size - br < bs) {
3369 rc = brecv(xsink,
"readHTTPChunkedBodyBinary", buf, 2 - br, 0, timeout,
false);
3373 se_closed(cname,
"readHTTPChunkedBodyBinary", xsink);
3380 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3382 if (recv_callback && !os) {
3383 if (runDataCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, *b,
true))
3390 assert(!recv_callback);
3407 if (!recv_callback && !os) {
3415 return recv_callback ? 0 : h.release();
3417 if (recv_callback) {
3420 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3421 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3424 if (recv_callback) {
3425 runHeaderCallback(xsink, cname,
"readHTTPChunkedBodyBinary", *recv_callback, l, h->
empty() ?
nullptr : *h,
3426 info.release(), false, obj);
3438 if (sock == QORE_INVALID_SOCKET) {
3439 se_not_open(cname,
"readHTTPChunkedBody", xsink);
3444 se_in_op(cname,
"readHTTPChunkedBody", xsink);
3447 se_in_op_thread(cname,
"readHTTPChunkedBody", xsink);
3452 if (http_exp_chunked_body)
3453 http_exp_chunked_body =
false;
3455 qore_socket_op_helper oh(
this);
3468 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 1, 0, timeout,
false);
3472 se_closed(cname,
"readHTTPChunkedBody", xsink);
3479 if (!state && c ==
'\r')
3481 else if (state && c ==
'\n')
3495 char* p = (
char*)strchr(str.
c_str(),
';');
3498 ssize_t size = strtol(str.
c_str(), 0, 16);
3499 do_chunked_read(QORE_EVENT_HTTP_CHUNK_SIZE, size, str.
strlen(), source);
3505 xsink->
raiseException(
"READ-HTTP-CHUNK-ERROR",
"negative value given for chunk size (%ld)", size);
3515 ssize_t bs = size < DEFAULT_SOCKET_BUFSIZE ? size : DEFAULT_SOCKET_BUFSIZE;
3520 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, bs, 0, timeout,
false);
3524 se_closed(cname,
"readHTTPChunkedBody", xsink);
3530 buf->concat(tbuf, rc);
3532 do_data_event(QORE_EVENT_HTTP_CHUNKED_DATA_READ, source, tbuf, (
size_t)rc);
3548 rc = brecv(xsink,
"readHTTPChunkedBody", tbuf, 2 - br, 0, timeout,
false);
3552 se_closed(cname,
"readHTTPChunkedBody", xsink);
3559 do_chunked_read(QORE_EVENT_HTTP_CHUNKED_DATA_RECEIVED, size, size + 2, source);
3561 if (recv_callback) {
3562 if (runDataCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, *buf,
true))
3575 if (!recv_callback) {
3583 return recv_callback ? 0 : h.release();
3585 if (recv_callback) {
3588 convertHeaderToHash(*h, (
char*)hdr->
c_str(), 0, *info,
nullptr,
"response-headers-raw");
3589 do_read_http_header(QORE_EVENT_HTTP_FOOTERS_RECEIVED, *h, source);
3592 if (recv_callback) {
3593 runHeaderCallback(xsink, cname,
"readHTTPChunkedBody", *recv_callback, l, h->
empty() ?
nullptr : *h,
3594 info.release(), false, obj);
3605 DLLLOCAL
static void do_accept_encoding(
char* t,
QoreHashNode& info) {
3614 while (*a && *a !=
';' && *a !=
',')
3618 l->push(str.release(),
nullptr);
3628 info.
setKeyValue(
"accept-encoding", l.release(), 0);
3631 DLLLOCAL
bool do_accept_charset(
char* t,
QoreHashNode& info) {
3632 bool acceptcharset =
false;
3647 if (*a ==
'u' || *a ==
'U') {
3649 if (*a ==
't' || *a ==
'T') {
3651 if (*a ==
'f' || *a ==
'F') {
3663 }
else if (*a ==
',') {
3667 }
else if (*a ==
';') {
3676 acceptcharset =
true;
3680 ac->concat(t, div - t);
3685 info.
setKeyValue(
"accept-charset", ac.release(), 0);
3686 acceptcharset =
true;
3690 return acceptcharset;
3695 bool* chunked =
nullptr,
const char* headers_raw_key =
"headers-raw") {
3696 bool close = !(flags & CHF_HTTP11);
3698 const char* senc =
nullptr;
3700 bool acceptcharset =
false;
3708 std::string raw_key;
3713 if ((p = strstr(buf,
"\r\n"))) {
3716 }
else if ((p = strchr(buf,
'\n'))) {
3719 }
else if ((p = strchr(buf,
'\r'))) {
3724 char* t = strchr(buf,
':');
3729 while (t && qore_isblank(*t))
3739 if (flags & CHF_PROCESS) {
3740 if (!strcmp(buf,
"connection")) {
3741 if (flags & CHF_HTTP11) {
3742 if (strcasestr(t,
"close"))
3745 if (strcasestr(t,
"keep-alive"))
3748 }
else if (!strcmp(buf,
"content-type")) {
3749 char* a = strcasestr(t,
"charset=");
3752 char* e = strchr(a + 8,
';');
3756 cs.
concat(a + 8, e - a - 8);
3766 size_t len = cs.
size();
3777 }
while (a > t && (*a ==
' ' || *a ==
';'));
3785 ct->concat(t, a - t + 1);
3792 info->
setKeyValue(
"body-content-type", ct.release(),
nullptr);
3798 ct = ct.substr(0, ct.find(
';'));
3799 if (utf8_content_type_set.find(ct) != utf8_content_type_set.end()) {
3803 senc = assume_http_encoding.c_str();
3808 info->
setKeyValue(
"body-content-type", val->refSelf(),
nullptr);
3811 }
else if (chunked && !strcmp(buf,
"transfer-encoding") && !strcasecmp(t,
"chunked")) {
3814 if (!strcmp(buf,
"accept-charset")) {
3815 acceptcharset = do_accept_charset(t, *info);
3816 }
else if ((flags & CHF_REQUEST) && !strcmp(buf,
"accept-encoding")) {
3817 do_accept_encoding(t, *info);
3823 if (raw_hdr && val) {
3824 val_copy = val->realCopy();
3828 hash_assignment_priv ha(*h, buf);
3829 if (!(*ha).isNothing()) {
3831 if ((*ha).getType() ==
NT_LIST) {
3835 l->
push(ha.swap(l),
nullptr);
3837 l->
push(val.release(),
nullptr);
3839 ha.assign(val.release(), 0);
3843 hash_assignment_priv ha(*raw_hdr, raw_key);
3844 if (!(*ha).isNothing()) {
3846 if ((*ha).getType() ==
NT_LIST) {
3850 l->
push(ha.swap(l),
nullptr);
3852 l->
push(val_copy.release(),
nullptr);
3854 ha.assign(val_copy.release(),
nullptr);
3858 if ((flags & CHF_PROCESS)) {
3864 if (info && !acceptcharset) {
3872 DLLLOCAL
int recvix(
const char* meth,
int len,
void* targ,
int timeout_ms,
ExceptionSink* xsink) {
3874 if (sock == QORE_INVALID_SOCKET) {
3875 se_not_open(
"Socket", meth, xsink,
"recvix");
3876 return QSE_NOT_OPEN;
3880 se_in_op(
"Socket", meth, xsink);
3883 se_in_op_thread(
"Socket", meth, xsink);
3887 PrivateQoreSocketThroughputHelper th(
this,
false);
3892 ssize_t rc = brecv(xsink, meth, buf, len - br, 0, timeout_ms);
3894 do_read_error(rc, meth, timeout_ms, xsink);
3898 memcpy(targ, buf, rc);
3906 do_data_event(QORE_EVENT_SOCKET_DATA_READ, QORE_SOURCE_SOCKET, targ, br);
3912 if (warn_callback_arg) {
3913 warn_callback_arg.
discard(xsink);
3916 warn_queue->deref(xsink);
3917 warn_queue =
nullptr;
3919 tp_warning_bs = 0.0;
3925 int64 min_ms = 1000) {
3928 if (warning_ms <= 0 && warning_bs <= 0) {
3929 xsink->
raiseException(
"SOCKET-SETWARNINGQUEUE-ERROR",
"Socket::setWarningQueue() at least one of warning "
3930 "ms argument: " QLLD
" and warning B/s argument: " QLLD
" must be greater than zero; to clear, call "\
3931 "Socket::clearWarningQueue() with no arguments", warning_ms, warning_bs);
3941 warn_queue->
deref(xsink);
3942 warn_callback_arg.
discard(xsink);
3945 warn_queue = qholder.release();
3946 warn_callback_arg = holder.release();
3947 tl_warning_us = (
int64)warning_ms * 1000;
3948 tp_warning_bs = warning_bs;
3949 tp_us_min = min_ms * 1000;
3952 DLLLOCAL
void getUsageInfo(
QoreHashNode& h, qore_socket_private& s)
const {
3960 h.
setKeyValue(
"bytes_sent", tp_bytes_sent + s.tp_bytes_sent, 0);
3961 h.
setKeyValue(
"bytes_recv", tp_bytes_recv + s.tp_bytes_sent, 0);
3962 h.
setKeyValue(
"us_sent", tp_us_sent + s.tp_us_sent, 0);
3963 h.
setKeyValue(
"us_recv", tp_us_recv + s.tp_us_recv, 0);
3986 DLLLOCAL
void clearStats() {
3993 DLLLOCAL
void doTimeoutWarning(
const char* op,
int64 dt) {
3995 assert(dt > tl_warning_us);
4003 if (warn_callback_arg)
4006 warn_queue->pushAndTakeRef(h);
4009 DLLLOCAL
void doThroughputWarning(
bool send,
int64 bytes,
int64 dt,
double bs) {
4011 assert(bs < tp_warning_bs);
4021 if (warn_callback_arg)
4024 warn_queue->pushAndTakeRef(h);
4027 DLLLOCAL
bool pendingHttpChunkedBody()
const {
4028 return http_exp_chunked_body && sock != QORE_INVALID_SOCKET;
4031 DLLLOCAL
void setSslVerifyMode(
int mode) {
4033 ssl_verify_mode = mode;
4035 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
4038 DLLLOCAL
void acceptAllCertificates(
bool accept_all =
true) {
4039 ssl_accept_all_certs = accept_all;
4041 ssl->setVerifyMode(ssl_verify_mode, ssl_accept_all_certs, client_target);
4046 ssl_err_str->
concat(
"; ");
4047 ssl_err_str->
concat(err_str);
4050 ssl_err_str = err_str;
4055 sock.priv->getUsageInfo(h, *s.priv);
4058 DLLLOCAL
static qore_socket_private* get(
QoreSocket& sock) {
4062 DLLLOCAL
static const qore_socket_private* get(
const QoreSocket& sock) {
4066 DLLLOCAL
static void captureRemoteCert(X509_STORE_CTX* x509_ctx);
DLLEXPORT const QoreEncoding * QCS_DEFAULT
the default encoding for the Qore library
DLLEXPORT const QoreEncoding * QCS_UTF8
UTF-8 multi-byte encoding (only UTF-8 and UTF-16 are multi-byte encodings)
Definition QoreEncoding.h:247
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