#include "abi.inc" #include "defs.inc" #define CURLOPT_URL 10002 #define CURLOPT_WRITEFUNCTION 20011 #define CURLOPT_WRITEDATA 10001 #define CURLOPT_HEADERFUNCTION 20079 #define CURLOPT_HEADERDATA 10029 #define CURLOPT_USERAGENT 10018 #define CURLOPT_HTTPHEADER 10023 #define CURLOPT_TIMEOUT_MS 155 #define CURLOPT_CONNECTTIMEOUT_MS 156 #define CURLOPT_ACCEPT_ENCODING 10102 #define CURLOPT_NOSIGNAL 99 #define CURLOPT_ERRORBUFFER 10010 #define CURLOPT_FOLLOWLOCATION 52 #define CURLINFO_RESPONSE_CODE 2097154 #define CURL_GLOBAL_DEFAULT 3 #define CURL_ERRSZ 256 #define HC_VALUE 0 #define HC_HAVE 128 #define HC_SIZE 136 #define HG_HDR -184 #define HG_ERRBUF -440 #define HG_HANDLE -448 #define HG_SLIST -456 #define HG_DEADLINE -464 #define HG_HASDL -472 #define HG_RA -480 #define HG_HASRA -488 #define HG_LASTST -496 #define HG_CODE -504 #define HG_ATTEMPT -512 #define HG_ACC503 -520 #define HG_OUTST -528 #define HG_CURLRC -536 #define HG_WAIT -544 #define HG_TMPL -552 #define RA_TM -104 #define RA_END -112 #define RA_DAY -120 #define RA_MON -128 #define RA_YEAR -136 #define RA_HH -144 #define RA_MI -152 #define RA_SS -160 .macro COPT_LONG opt, val mov HG_HANDLE(%rbp), %rdi mov $\opt, %esi mov $\val, %rdx xor %eax, %eax call curl_easy_setopt@PLT .endm .macro COPT_REG opt, reg mov HG_HANDLE(%rbp), %rdi mov $\opt, %esi mov \reg, %rdx xor %eax, %eax call curl_easy_setopt@PLT .endm .text PUBFUNC cepis_global_init PROLOGUE 8 xor %eax, %eax mov $1, %ecx lock cmpxchgl %ecx, cepis__curl_state(%rip) jne .Lonce_out mov $CURL_GLOBAL_DEFAULT, %edi call curl_global_init@PLT movl $2, cepis__curl_state(%rip) .Lonce_out: EPILOGUE ret ENDFUNC cepis_global_init PUBFUNC cepis_global_cleanup PROLOGUE 8 call cepis__default_client_destroy cmpl $0, cepis__curl_state(%rip) je .Lgc_out movl $0, cepis__curl_state(%rip) call curl_global_cleanup@PLT .Lgc_out: EPILOGUE ret ENDFUNC cepis_global_cleanup FUNC cepis__mono PROLOGUE 24 mov $1, %edi lea LOCAL1(%rbp), %rsi call clock_gettime@PLT cvtsi2sdq LOCAL1(%rbp), %xmm0 cvtsi2sdq LOCAL0(%rbp), %xmm1 mulsd .Lnano(%rip), %xmm1 addsd %xmm1, %xmm0 EPILOGUE ret ENDFUNC cepis__mono FUNC cepis__sleep PROLOGUE 40 xorpd %xmm1, %xmm1 comisd %xmm1, %xmm0 jbe .Lsleep_out cvttsd2siq %xmm0, %rax mov %rax, LOCAL1(%rbp) cvtsi2sdq %rax, %xmm1 subsd %xmm1, %xmm0 mulsd .Lgiga(%rip), %xmm0 cvttsd2siq %xmm0, %rax cmp $0, %rax jge .Lsleep_store xor %eax, %eax .Lsleep_store: mov %rax, LOCAL0(%rbp) .Lsleep_call: lea LOCAL1(%rbp), %rdi lea LOCAL3(%rbp), %rsi call nanosleep@PLT test %eax, %eax jz .Lsleep_out call __errno_location@PLT cmpl $4, (%rax) jne .Lsleep_out mov LOCAL3(%rbp), %rax mov %rax, LOCAL1(%rbp) mov LOCAL2(%rbp), %rax mov %rax, LOCAL0(%rbp) jmp .Lsleep_call .Lsleep_out: EPILOGUE ret ENDFUNC cepis__sleep FUNC cepis__rand01 mov CL_RNG(%rdi), %rax .Lrand_loop: mov %rax, %r8 mov %r8, %rdx shl $13, %rdx xor %rdx, %r8 mov %r8, %rdx shr $7, %rdx xor %rdx, %r8 mov %r8, %rdx shl $17, %rdx xor %rdx, %r8 lock cmpxchgq %r8, CL_RNG(%rdi) jne .Lrand_loop mov %r8, %rax shr $11, %rax cvtsi2sdq %rax, %xmm0 mulsd .Ltwo53(%rip), %xmm0 ret ENDFUNC cepis__rand01 FUNC cepis__backoff PROLOGUE 24 mov %rdi, %rbx test %edx, %edx jz .Lbo_calc movsd CL_BACKOFF_MAX(%rbx), %xmm1 minsd %xmm1, %xmm0 xorpd %xmm1, %xmm1 maxsd %xmm1, %xmm0 EPILOGUE ret .Lbo_calc: movsd CL_BACKOFF_BASE(%rbx), %xmm0 movsd CL_BACKOFF_MAX(%rbx), %xmm1 mov %esi, %ecx dec %ecx .Lbo_loop: test %ecx, %ecx jle .Lbo_cap comisd %xmm1, %xmm0 jae .Lbo_cap addsd %xmm0, %xmm0 dec %ecx jmp .Lbo_loop .Lbo_cap: minsd %xmm1, %xmm0 movsd %xmm0, LOCAL0(%rbp) mov %rbx, %rdi call cepis__rand01 mulsd LOCAL0(%rbp), %xmm0 EPILOGUE ret ENDFUNC cepis__backoff FUNC cepis__read_uint xor %ecx, %ecx xor %r8d, %r8d movl $0, (%rsi) .Lru_loop: cmp %edx, %r8d jae .Lru_end movzbl (%rdi), %eax cmp $'0', %al jb .Lru_end cmp $'9', %al ja .Lru_end sub $'0', %eax imul $10, %ecx, %ecx add %eax, %ecx inc %rdi inc %r8d jmp .Lru_loop .Lru_end: test %r8d, %r8d jz .Lru_bad mov %ecx, (%rsi) mov %rdi, %rax ret .Lru_bad: xor %eax, %eax ret ENDFUNC cepis__read_uint FUNC cepis__skip_blanks .Lsb_loop: movzbl (%rdi), %eax cmp $' ', %al je .Lsb_adv cmp $9, %al je .Lsb_adv mov %rdi, %rax ret .Lsb_adv: inc %rdi jmp .Lsb_loop ENDFUNC cepis__skip_blanks FUNC cepis__retry_after PROLOGUE 120 mov %rsi, %r14 call cepis__skip_blanks mov %rax, %rbx cmpb $0, (%rbx) je .Lra_bad mov %rbx, %rdi lea RA_END(%rbp), %rsi call strtod@PLT mov RA_END(%rbp), %rax cmp %rbx, %rax je .Lra_date movsd %xmm0, LOCAL0(%rbp) mov %rax, %rdi call cepis__skip_blanks movzbl (%rax), %ecx test %cl, %cl jz .Lra_numeric cmp $13, %cl je .Lra_numeric cmp $10, %cl je .Lra_numeric jmp .Lra_date .Lra_numeric: movsd LOCAL0(%rbp), %xmm0 xorpd %xmm1, %xmm1 maxsd %xmm1, %xmm0 movsd %xmm0, (%r14) mov $1, %eax EPILOGUE ret .Lra_date: mov %rbx, %r12 .Lra_findnum: movzbl (%r12), %eax test %al, %al jz .Lra_bad cmp $'0', %al jb .Lra_findnum_adv cmp $'9', %al jbe .Lra_day .Lra_findnum_adv: inc %r12 jmp .Lra_findnum .Lra_day: mov %r12, %rdi lea RA_DAY(%rbp), %rsi mov $2, %edx call cepis__read_uint test %rax, %rax jz .Lra_bad mov %rax, %rdi call cepis__skip_blanks mov %rax, %r12 xor %r13d, %r13d .Lra_mon_loop: cmp $12, %r13d jae .Lra_bad lea cepis__months(%rip), %rax mov (%rax, %r13, 8), %rsi mov %r12, %rdi mov $3, %rdx call strncasecmp@PLT test %eax, %eax jz .Lra_mon_hit inc %r13d jmp .Lra_mon_loop .Lra_mon_hit: mov %r13d, RA_MON(%rbp) lea 3(%r12), %rdi call cepis__skip_blanks mov %rax, %rdi lea RA_YEAR(%rbp), %rsi mov $4, %edx call cepis__read_uint test %rax, %rax jz .Lra_bad mov %rax, %rdi call cepis__skip_blanks mov %rax, %rdi lea RA_HH(%rbp), %rsi mov $2, %edx call cepis__read_uint test %rax, %rax jz .Lra_bad cmpb $':', (%rax) jne .Lra_bad lea 1(%rax), %rdi lea RA_MI(%rbp), %rsi mov $2, %edx call cepis__read_uint test %rax, %rax jz .Lra_bad cmpb $':', (%rax) jne .Lra_bad lea 1(%rax), %rdi lea RA_SS(%rbp), %rsi mov $2, %edx call cepis__read_uint test %rax, %rax jz .Lra_bad lea RA_TM(%rbp), %rdi xor %esi, %esi mov $56, %rdx call memset@PLT mov RA_SS(%rbp), %eax mov %eax, RA_TM+0(%rbp) mov RA_MI(%rbp), %eax mov %eax, RA_TM+4(%rbp) mov RA_HH(%rbp), %eax mov %eax, RA_TM+8(%rbp) mov RA_DAY(%rbp), %eax mov %eax, RA_TM+12(%rbp) mov RA_MON(%rbp), %eax mov %eax, RA_TM+16(%rbp) mov RA_YEAR(%rbp), %eax sub $1900, %eax mov %eax, RA_TM+20(%rbp) movl $-1, RA_TM+32(%rbp) lea RA_TM(%rbp), %rdi call timegm@PLT cmp $-1, %rax je .Lra_bad mov %rax, %rbx xor %edi, %edi call time@PLT sub %rax, %rbx cmp $0, %rbx jge .Lra_diff xor %ebx, %ebx .Lra_diff: cvtsi2sdq %rbx, %xmm0 movsd %xmm0, (%r14) mov $1, %eax EPILOGUE ret .Lra_bad: xor %eax, %eax EPILOGUE ret ENDFUNC cepis__retry_after FUNC cepis__write_cb PROLOGUE 24 mov %rdi, %r12 mov %rsi, %rax imul %rdx, %rax mov %rax, %r13 mov %rcx, %rdi mov %r12, %rsi mov %r13, %rdx call cepis__buf_append test %eax, %eax jnz .Lwcb_fail mov %r13, %rax EPILOGUE ret .Lwcb_fail: xor %eax, %eax EPILOGUE ret ENDFUNC cepis__write_cb FUNC cepis__header_cb PROLOGUE 24 mov %rdi, %r12 mov %rsi, %rax imul %rdx, %rax mov %rax, %r13 mov %rcx, %rbx cmp $12, %r13 jb .Lhcb_out mov %r12, %rdi lea .Lhdr_retry_after(%rip), %rsi mov $12, %rdx call strncasecmp@PLT test %eax, %eax jnz .Lhcb_out lea 12(%r12), %r14 mov %r12, %r15 add %r13, %r15 .Lhcb_lead: cmp %r15, %r14 jae .Lhcb_copy movzbl (%r14), %eax cmp $' ', %al je .Lhcb_lead_adv cmp $9, %al jne .Lhcb_trail .Lhcb_lead_adv: inc %r14 jmp .Lhcb_lead .Lhcb_trail: cmp %r15, %r14 jae .Lhcb_copy movzbl -1(%r15), %eax cmp $' ', %al je .Lhcb_trail_adv cmp $9, %al je .Lhcb_trail_adv cmp $13, %al je .Lhcb_trail_adv cmp $10, %al je .Lhcb_trail_adv jmp .Lhcb_copy .Lhcb_trail_adv: dec %r15 jmp .Lhcb_trail .Lhcb_copy: mov %r15, %rdx sub %r14, %rdx cmp $127, %rdx jbe .Lhcb_do mov $127, %rdx .Lhcb_do: mov %rdx, LOCAL0(%rbp) mov %rbx, %rdi mov %r14, %rsi call memcpy@PLT mov LOCAL0(%rbp), %rdx movb $0, (%rbx, %rdx, 1) movl $1, HC_HAVE(%rbx) .Lhcb_out: mov %r13, %rax EPILOGUE ret ENDFUNC cepis__header_cb FUNC cepis__http_get PROLOGUE 520 mov %rdi, %rbx mov %rsi, %r12 mov %edx, %eax mov %eax, HG_ACC503(%rbp) mov %rcx, HG_OUTST(%rbp) mov %r8, %r13 mov %r9, %r14 movl $0, (%rcx) movl $0, HG_LASTST(%rbp) movl $0, HG_HASRA(%rbp) movl $0, HG_CURLRC(%rbp) movq $0, HG_RA(%rbp) movb $0, HG_ERRBUF(%rbp) call cepis_global_init movsd CL_TOTAL_TIMEOUT(%rbx), %xmm0 xorpd %xmm1, %xmm1 comisd %xmm1, %xmm0 jbe .Lhg_nodl call cepis__mono addsd CL_TOTAL_TIMEOUT(%rbx), %xmm0 movsd %xmm0, HG_DEADLINE(%rbp) movl $1, HG_HASDL(%rbp) jmp .Lhg_start .Lhg_nodl: movl $0, HG_HASDL(%rbp) .Lhg_start: movl $1, HG_ATTEMPT(%rbp) .Lhg_attempt: cmpl $0, HG_HASDL(%rbp) je .Lhg_go call cepis__mono comisd HG_DEADLINE(%rbp), %xmm0 jae .Lhg_exhausted .Lhg_go: mov %r13, %rdi call cepis__buf_reset lea HG_HDR(%rbp), %rdi movl $0, HC_HAVE(%rdi) movb $0, HC_VALUE(%rdi) movb $0, HG_ERRBUF(%rbp) movq $0, HG_SLIST(%rbp) call curl_easy_init@PLT test %rax, %rax jz .Lhg_nomem mov %rax, HG_HANDLE(%rbp) xor %edi, %edi lea .Lhdr_accept(%rip), %rsi call curl_slist_append@PLT mov %rax, HG_SLIST(%rbp) COPT_REG CURLOPT_URL, %r12 lea cepis__write_cb(%rip), %rax COPT_REG CURLOPT_WRITEFUNCTION, %rax COPT_REG CURLOPT_WRITEDATA, %r13 lea cepis__header_cb(%rip), %rax COPT_REG CURLOPT_HEADERFUNCTION, %rax lea HG_HDR(%rbp), %rax COPT_REG CURLOPT_HEADERDATA, %rax mov CL_USER_AGENT(%rbx), %rax COPT_REG CURLOPT_USERAGENT, %rax mov HG_SLIST(%rbp), %rax COPT_REG CURLOPT_HTTPHEADER, %rax lea .Lidentity(%rip), %rax COPT_REG CURLOPT_ACCEPT_ENCODING, %rax lea HG_ERRBUF(%rbp), %rax COPT_REG CURLOPT_ERRORBUFFER, %rax COPT_LONG CURLOPT_NOSIGNAL, 1 COPT_LONG CURLOPT_FOLLOWLOCATION, 0 movsd CL_TIMEOUT(%rbx), %xmm0 mulsd .Lthousand(%rip), %xmm0 cvttsd2siq %xmm0, %rax cmp $1, %rax jge .Lhg_tmo mov $1, %rax .Lhg_tmo: mov %rax, HG_TMPL(%rbp) COPT_REG CURLOPT_TIMEOUT_MS, %rax mov HG_TMPL(%rbp), %rax COPT_REG CURLOPT_CONNECTTIMEOUT_MS, %rax mov HG_HANDLE(%rbp), %rdi call curl_easy_perform@PLT mov %eax, HG_CURLRC(%rbp) test %eax, %eax jnz .Lhg_network mov HG_HANDLE(%rbp), %rdi mov $CURLINFO_RESPONSE_CODE, %esi lea HG_CODE(%rbp), %rdx xor %eax, %eax call curl_easy_getinfo@PLT mov HG_CODE(%rbp), %rax mov %eax, %r15d cmp $200, %r15d je .Lhg_accept cmpl $0, HG_ACC503(%rbp) je .Lhg_notaccept cmp $503, %r15d je .Lhg_accept .Lhg_notaccept: cmp $429, %r15d je .Lhg_retriable cmp $500, %r15d je .Lhg_retriable cmp $502, %r15d je .Lhg_retriable cmp $503, %r15d je .Lhg_retriable cmp $504, %r15d je .Lhg_retriable .Lhg_accept: mov HG_OUTST(%rbp), %rax mov %r15d, (%rax) lea HG_HANDLE(%rbp), %rdi lea HG_SLIST(%rbp), %rsi call cepis__curl_release xor %eax, %eax EPILOGUE ret .Lhg_retriable: mov %r15d, HG_LASTST(%rbp) movl $0, HG_HASRA(%rbp) lea HG_HDR(%rbp), %rax cmpl $0, HC_HAVE(%rax) je .Lhg_after lea HG_HDR(%rbp), %rdi lea HG_RA(%rbp), %rsi call cepis__retry_after mov %eax, HG_HASRA(%rbp) jmp .Lhg_after .Lhg_network: movl $0, HG_LASTST(%rbp) movl $0, HG_HASRA(%rbp) .Lhg_after: lea HG_HANDLE(%rbp), %rdi lea HG_SLIST(%rbp), %rsi call cepis__curl_release mov HG_ATTEMPT(%rbp), %eax cmp CL_MAX_ATTEMPTS(%rbx), %eax jge .Lhg_exhausted mov %rbx, %rdi mov HG_ATTEMPT(%rbp), %esi movsd HG_RA(%rbp), %xmm0 mov HG_HASRA(%rbp), %edx call cepis__backoff movsd %xmm0, HG_WAIT(%rbp) cmpl $0, HG_HASDL(%rbp) je .Lhg_sleep call cepis__mono movsd HG_DEADLINE(%rbp), %xmm1 subsd %xmm0, %xmm1 xorpd %xmm2, %xmm2 comisd %xmm2, %xmm1 jbe .Lhg_exhausted movsd HG_WAIT(%rbp), %xmm0 minsd %xmm1, %xmm0 movsd %xmm0, HG_WAIT(%rbp) .Lhg_sleep: movsd HG_WAIT(%rbp), %xmm0 call cepis__sleep incl HG_ATTEMPT(%rbp) jmp .Lhg_attempt .Lhg_exhausted: mov CL_MAX_ATTEMPTS(%rbx), %r15d cmpl $429, HG_LASTST(%rbp) je .Lhg_rate cmpl $0, HG_LASTST(%rbp) jne .Lhg_server test %r14, %r14 jz .Lhg_ret_network mov HG_CURLRC(%rbp), %edi call curl_easy_strerror@PLT mov %rax, %r9 cmpb $0, HG_ERRBUF(%rbp) je .Lhg_net_msg lea HG_ERRBUF(%rbp), %r9 .Lhg_net_msg: lea E_MESSAGE(%r14), %rdi mov $E_MSGLEN, %esi lea .Lfmt_network(%rip), %rdx mov %r12, %rcx mov %r15d, %r8d xor %eax, %eax call snprintf@PLT movl $CEPIS_ERR_NETWORK, E_STATUS(%r14) .Lhg_ret_network: mov $CEPIS_ERR_NETWORK, %eax EPILOGUE ret .Lhg_server: test %r14, %r14 jz .Lhg_ret_server mov HG_LASTST(%rbp), %eax mov %eax, E_HTTP_STATUS(%r14) movl $CEPIS_ERR_SERVER, E_STATUS(%r14) lea E_MESSAGE(%r14), %rdi mov $E_MSGLEN, %esi lea .Lfmt_server(%rip), %rdx mov HG_LASTST(%rbp), %ecx mov %r12, %r8 mov %r15d, %r9d xor %eax, %eax call snprintf@PLT .Lhg_ret_server: mov $CEPIS_ERR_SERVER, %eax EPILOGUE ret .Lhg_rate: test %r14, %r14 jz .Lhg_ret_rate movl $429, E_HTTP_STATUS(%r14) movl $CEPIS_ERR_RATE_LIMITED, E_STATUS(%r14) cmpl $0, HG_HASRA(%rbp) je .Lhg_rate_msg movsd HG_RA(%rbp), %xmm0 movsd %xmm0, E_RETRY_AFTER(%r14) .Lhg_rate_msg: lea E_MESSAGE(%r14), %rdi mov $E_MSGLEN, %esi lea .Lfmt_rate(%rip), %rdx mov %r12, %rcx mov %r15d, %r8d xor %eax, %eax call snprintf@PLT .Lhg_ret_rate: mov $CEPIS_ERR_RATE_LIMITED, %eax EPILOGUE ret .Lhg_nomem: mov $CEPIS_ERR_NOMEM, %eax EPILOGUE ret ENDFUNC cepis__http_get FUNC cepis__curl_release PROLOGUE 8 mov %rdi, %rbx mov %rsi, %r12 mov (%rbx), %rdi test %rdi, %rdi jz .Lrel_slist call curl_easy_cleanup@PLT movq $0, (%rbx) .Lrel_slist: mov (%r12), %rdi test %rdi, %rdi jz .Lrel_out call curl_slist_free_all@PLT movq $0, (%r12) .Lrel_out: EPILOGUE ret ENDFUNC cepis__curl_release .section .rodata .p2align 3 .Lnano: .double 1e-9 .Lgiga: .double 1e9 .Ltwo53: .double 1.1102230246251565e-16 .Lthousand: .double 1000.0 .Lhdr_retry_after: .asciz "retry-after:" .Lhdr_accept: .asciz "Accept: application/json, text/csv;q=0.9, */*;q=0.1" .Lidentity: .asciz "identity" .Lfmt_network: .asciz "could not reach %s after %d attempt(s): %s" .Lfmt_server: .asciz "the API answered %d at %s after %d attempt(s)" .Lfmt_rate: .asciz "rate limit reached at %s after %d attempt(s)" .Ls_jan: .asciz "Jan" .Ls_feb: .asciz "Feb" .Ls_mar: .asciz "Mar" .Ls_apr: .asciz "Apr" .Ls_may: .asciz "May" .Ls_jun: .asciz "Jun" .Ls_jul: .asciz "Jul" .Ls_aug: .asciz "Aug" .Ls_sep: .asciz "Sep" .Ls_oct: .asciz "Oct" .Ls_nov: .asciz "Nov" .Ls_dec: .asciz "Dec" .section .data.rel.ro,"aw",@progbits .p2align 3 cepis__months: .quad .Ls_jan, .Ls_feb, .Ls_mar, .Ls_apr, .Ls_may, .Ls_jun .quad .Ls_jul, .Ls_aug, .Ls_sep, .Ls_oct, .Ls_nov, .Ls_dec .data .p2align 2 cepis__curl_state: .long 0 .section .note.GNU-stack,"",@progbits