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: