Annotation of parser3/src/main/pa_socks.C, revision 1.41
1.3 paf 1: /** @file
1.1 paf 2: Parser: socks initialization/finalization.
3:
1.35 moko 4: Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
1.32 moko 5: Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
1.15 paf 6: */
1.1 paf 7:
1.41 ! moko 8: volatile const char * IDENT_PA_SOCKS_C="$Id: pa_socks.C,v 1.40 2026/10/18 18:15:24 moko Exp $";
1.2 paf 9:
10: #include "pa_config_includes.h"
1.36 moko 11: #include "pa_socks.h"
1.1 paf 12:
1.28 moko 13: #ifdef _MSC_VER
14:
1.9 paf 15: #include "pa_exception.h"
1.19 paf 16: #include "pa_string.h"
1.11 paf 17:
1.19 paf 18: #include <windows.h>
19:
1.1 paf 20: WSADATA wsaData;
21:
1.22 paf 22: void pa_socks_init() {
1.1 paf 23: WORD wVersionRequested;
24: int err;
25: wVersionRequested = MAKEWORD( 1, 1 );
26: err = WSAStartup( wVersionRequested, &wsaData );
27: if ( err != 0 ) {
1.28 moko 28: /* Tell the user that we could not find a usable */
1.33 moko 29: throw Exception(0, 0, "cannot WSAStartup, err=%d", err);
1.1 paf 30: }
31: }
32:
1.22 paf 33: void pa_socks_done() {
1.1 paf 34: /* Confirm that the WinSock DLL supports 2.2.*/
35: /* Note that if the DLL supports versions greater */
36: /* than 2.2 in addition to 2.2, it will still return */
37: /* 2.2 in wVersion since that is the version we */
38: /* requested. */
1.28 moko 39: if ( LOBYTE( wsaData.wVersion ) == 2 || HIBYTE( wsaData.wVersion ) == 2 ) {
40: WSACleanup();
41: return;
1.1 paf 42: }
43: }
44:
1.23 paf 45: const char* pa_socks_strerr(int no) {
46: char buf[MAX_STRING];
47: buf[0]=0;
48: size_t error_size=FormatMessage(
49: FORMAT_MESSAGE_FROM_SYSTEM |
50: FORMAT_MESSAGE_IGNORE_INSERTS,
51: NULL,
52: no,
53: 0, // Default language
54: (LPTSTR) &buf,
55: sizeof(buf),
56: NULL
57: );
58: if(error_size>3) // ".\r\n"
59: buf[error_size-3]=0;
60: return buf[0]? pa_strdup(buf): "unknown error";
61: }
62: int pa_socks_errno() {
63: return WSAGetLastError();
64: }
65:
1.37 moko 66: bool pa_socks_is_reset(int no) {
67: return no==WSAECONNRESET || no==WSAECONNABORTED;
68: }
69:
1.38 moko 70: bool pa_socks_is_interrupted(int no) {
71: return no==WSAEINTR;
72: }
73:
1.40 moko 74: // there are no signals, calls are not restarted for the time left
75: typedef int sock_time;
76:
77: static sock_time sock_now() {
78: return 0;
79: }
80:
81: static bool sock_ready_within_remaining_timeout(SOCKET, bool, sock_time) {
82: return false;
83: }
84:
1.36 moko 85: int pa_sock_ready(SOCKET sock, bool for_write, int timeout_ms) {
86: WSAPOLLFD fd={sock, (SHORT)(for_write ? POLLWRNORM : POLLRDNORM), 0};
87: return WSAPoll(&fd, 1, timeout_ms);
88: }
89:
1.41 ! moko 90: int pa_sock_connect(SOCKET sock, const struct sockaddr *addr, socklen_t addrlen) {
! 91: return connect(sock, addr, addrlen);
! 92: }
! 93:
1.1 paf 94: #else
1.10 paf 95:
1.36 moko 96: #include <poll.h>
1.41 ! moko 97: #include "pa_request.h"
1.36 moko 98:
1.22 paf 99: void pa_socks_init() {}
100: void pa_socks_done() {}
1.23 paf 101:
102: const char* pa_socks_strerr(int no) {
103: return strerror(no);
104: }
105: int pa_socks_errno() {
106: return errno;
107: }
1.1 paf 108:
1.37 moko 109: bool pa_socks_is_reset(int no) {
110: return no==ECONNRESET;
111: }
112:
1.38 moko 113: bool pa_socks_is_interrupted(int no) {
1.41 ! moko 114: // the request is interrupted by the response timeout: the error does not matter
! 115: if(thread_request && thread_request->get_skip()==Request::SKIP_INTERRUPTED)
! 116: thread_request->throw_interrupted();
1.38 moko 117: return no==EINTR;
118: }
119:
1.40 moko 120: typedef struct timeval sock_time;
121:
122: static sock_time sock_now() {
123: sock_time now;
124: gettimeofday(&now, 0);
125: return now;
126: }
127:
128: static long long timeval_ms(const struct timeval &tv) {
129: return (long long)tv.tv_sec*1000+tv.tv_usec/1000;
130: }
131:
1.36 moko 132: int pa_sock_ready(SOCKET sock, bool for_write, int timeout_ms) {
133: struct pollfd fd={sock, (short)(for_write ? POLLOUT : POLLIN), 0};
1.40 moko 134: sock_time start=sock_now();
1.39 moko 135:
136: int left=timeout_ms;
137: int result;
1.40 moko 138: // GC stops the threads with signals: continue poll for the time left
1.39 moko 139: while((result=poll(&fd, 1, left))<0 && pa_socks_is_interrupted(errno)) {
1.40 moko 140: if(timeout_ms>0){
141: long long passed=timeval_ms(sock_now()) - timeval_ms(start);
142: if(passed>=timeout_ms)
143: return 0;
144: left=passed<0 ? timeout_ms : timeout_ms-(int)passed;
145: }
1.39 moko 146: }
147: return result;
1.36 moko 148: }
149:
1.40 moko 150: // the system restarts recv/send with the whole socket timeout again, under load it would never expire: wait for the remaining time
151: static bool sock_ready_within_remaining_timeout(SOCKET sock, bool for_write, sock_time start) {
152: struct timeval socket_timeout;
153: socklen_t timeout_size=sizeof(socket_timeout);
154: if(getsockopt(sock, SOL_SOCKET, for_write ? SO_SNDTIMEO : SO_RCVTIMEO, &socket_timeout, &timeout_size)<0 || !(socket_timeout.tv_sec || socket_timeout.tv_usec))
1.41 ! moko 155: return pa_sock_ready(sock, for_write, -1)>0; // no timeout
1.40 moko 156:
157: long long passed=timeval_ms(sock_now())-timeval_ms(start);
158: long long left=timeval_ms(socket_timeout)-passed;
159: int ready=left>0 ? pa_sock_ready(sock, for_write, left<INT_MAX ? (int)left : INT_MAX) : 0;
160: if(ready==0)
161: errno=EAGAIN;
162: return ready>0;
163: }
164:
1.41 ! moko 165: int pa_sock_connect(SOCKET sock, const struct sockaddr *addr, socklen_t addrlen) {
! 166: sock_time start=sock_now();
! 167: if(connect(sock, addr, addrlen)==0)
! 168: return 0;
! 169: if(!pa_socks_is_interrupted(errno))
! 170: return -1;
! 171:
! 172: // the connection goes on in the background
! 173: if(!sock_ready_within_remaining_timeout(sock, true, start))
! 174: return -1;
! 175:
! 176: int error=0;
! 177: socklen_t error_size=sizeof(error);
! 178: if(getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &error_size)<0)
! 179: return -1;
! 180: if(!error)
! 181: return 0;
! 182: errno=error;
! 183: return -1;
! 184: }
! 185:
1.1 paf 186: #endif
1.38 moko 187:
188: ssize_t pa_sock_recv(SOCKET sock, char *buf, size_t len) {
1.40 moko 189: sock_time start=sock_now();
1.38 moko 190: ssize_t result;
1.40 moko 191: while((result=recv(sock, buf, len, 0)) < 0 && pa_socks_is_interrupted(pa_socks_errno()) && sock_ready_within_remaining_timeout(sock, false, start));
1.38 moko 192: return result;
193: }
194:
195: ssize_t pa_sock_send(SOCKET sock, const char *buf, size_t len) {
1.40 moko 196: sock_time start=sock_now();
1.38 moko 197: ssize_t result;
1.40 moko 198: while((result=send(sock, buf, len, 0)) < 0 && pa_socks_is_interrupted(pa_socks_errno()) && sock_ready_within_remaining_timeout(sock, true, start));
1.38 moko 199: return result;
200: }
E-mail: