Unnamed Fossil Project

Check-in [ae6a246127]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:updated
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:ae6a24612777efc15f9be6cdac60c39419f0badf
User & Date: alexey@sudachen.name 2012-07-20 05:06:40
Context
2012-07-20
05:07
updated check-in: 6d74618ec6 user: alexey@sudachen.name tags: trunk
05:06
updated check-in: ae6a246127 user: alexey@sudachen.name tags: trunk
2012-06-17
10:30
updated check-in: 3ac5a21038 user: alexey@sudachen.name tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to asio.hc.

39
40
41
42
43
44
45

46
47
48
49
50
51
52
...
576
577
578
579
580
581
582



Except as contained in this notice, the name of a copyright holder shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization of the copyright holder.

*/


#ifndef C_once_5F140392_CCAA_4FE1_88CB_DC84EE3B25A0
#define C_once_5F140392_CCAA_4FE1_88CB_DC84EE3B25A0

#ifdef _LIBYOYO
#define _YOYO_ASIO_BUILTIN
#endif

................................................................................
    return Asio_St_Count;
  }
#endif
  ;
  
#endif /* C_once_5F140392_CCAA_4FE1_88CB_DC84EE3B25A0 */










>







 







>
>
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
577
578
579
580
581
582
583
584
585

Except as contained in this notice, the name of a copyright holder shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization of the copyright holder.

*/

#if 0
#ifndef C_once_5F140392_CCAA_4FE1_88CB_DC84EE3B25A0
#define C_once_5F140392_CCAA_4FE1_88CB_DC84EE3B25A0

#ifdef _LIBYOYO
#define _YOYO_ASIO_BUILTIN
#endif

................................................................................
    return Asio_St_Count;
  }
#endif
  ;
  
#endif /* C_once_5F140392_CCAA_4FE1_88CB_DC84EE3B25A0 */


#endif

Changes to httpd.hc.

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
137
138
139
140
141
142
143

144
145
146
147
148
149
150
...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402


403
404


405
406
407
408
409
410
411
412
413
414

415
416
417
418
419
420
421
422
423
424
425
426
427
428

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480


481
482


483
484
485
486
487
488
489
490
491
492
493
494

495
496
497
498
499
500
501
...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
...
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601


602
603


604
605
606
607

608
609


610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661

662
663

664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679

680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
...
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
#include "yoyo.hc"
#include "string.hc"
#include "buffer.hc"
#include "dicto.hc"
#include "file.hc"
#include "tcpip.hc"
#include "url.hc"
#include "asio.hc"

#ifdef _LIBYOYO
#define _YOYO_HTTPD_BUILTIN
#endif

struct _YOYO_HTTPD_REQUEST;
typedef int (*httpd_callback_t)(void *obj, struct _YOYO_HTTPD_REQUEST *rqst, int status);
................................................................................
#ifdef _YOYO_HTTPD_BUILTIN
  {
    Httpd_Detach_Request(rqst);
    __Unrefe(rqst->httpd);
    __Unrefe(rqst->sok);
    free(rqst->remote_addr);
    free(rqst->uri);

    __Unrefe(rqst->bf);
    __Unrefe(rqst->qhdr);
    __Unrefe(rqst->instrm);
    __Unrefe(rqst->outstrm);
    free(rqst->outstrm_type);
    free(rqst->location);
    free(rqst->cache_control);
................................................................................
            bf->count += L;
          }
      }
  }  
#endif
  ;
  
int Cbk_Httpd_Sending_Result(void *_rqst, int status)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    int L;
    YOYO_HTTPD_REQUEST *rqst = _rqst;
    YOYO_BUFFER *bf = rqst->bf;

    if ( status == ASIO_TIMER )
      return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_TIMER),0;
    if ( !ASIO_ST_SUCCEEDED(status) )


      return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_IOFAIL),
             Tcp_Close(rqst->sok),0;


    
    if ( rqst->outstrm )
      if ( rqst->outstrm_length )
        {
          if ( !rqst->left ) goto finished;
          L = Yo_Minu(rqst->left,bf->capacity);
          L = Oj_Read(rqst->outstrm,bf->at,L,0);
          if ( !L ) goto finished;
          rqst->left -= L;
          return Tcp_Asio_Send(rqst->sok,bf->at,L,rqst,Cbk_Httpd_Sending_Result);

        }
      else /*chunked*/
        {
          int i, j;
          char len[30];
          L = bf->capacity - 32;        
          L = Oj_Read(rqst->outstrm,bf->at+30,L,0);
          sprintf(len,"%x\r\n",L);
          i = strlen(len);
          j = 30-i;
          memcpy(bf->at+j,len,i);
          memcpy(bf->at+30+L,"\r\n",2);
          if ( !L ) { rqst->outstrm_length = -1; rqst->left = 0; }
          return Tcp_Asio_Send(rqst->sok,bf->at,L,rqst,Cbk_Httpd_Sending_Result);

        }
      
  finished:
    rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_FINISHED);
    Tcp_Graceful_Close(rqst->sok);
    return 0;
  }
#endif
  ;
  
void Httpd_Continue_Request(YOYO_HTTPD_REQUEST *rqst, int st)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    YOYO_BUFFER *bf = rqst->bf;
    Httpd_Gen_Response(rqst,st);
    Tcp_Asio_Send(rqst->sok,bf->at,bf->count,rqst,Cbk_Httpd_Sending_Result);
  }
#endif
  ;
  
void Httpd_Perform_Request(YOYO_HTTPD_REQUEST *rqst)
#ifdef _YOYO_HTTPD_BUILTIN
  {
................................................................................
    st = rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_RQST_PERFORM);
    if ( st )
      Httpd_Continue_Request(rqst,st);
  }
#endif
  ;
    
int Cbk_Httpd_Getting_Postdta(void *_rqst, int status, int count)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    YOYO_HTTPD_REQUEST *rqst = _rqst;
    YOYO_BUFFER *bf = rqst->bf;
    
    if ( status == ASIO_TIMER )
      return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_TIMER),0;
    if ( !ASIO_ST_SUCCEEDED(status) )


      return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_IOFAIL),
             Tcp_Close(rqst->sok),0;



    bf->count += count;
    rqst->left -= count;
    
    if ( rqst->instrm || bf->count > HTTPD_MAXBUF_POSTDATA_LENGTH )
      {
        if ( !rqst->instrm ) 
          {
            if ( HTTPD_ACCEPT != rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_RQST_POSTDTA) )
              {
                return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_LONGRQST),
                        Tcp_Close(rqst->sok),0;

              }
            if ( !rqst->instrm )
              rqst->instrm = __Refe(Cfile_Temp());
          }
        Oj_Write(rqst->instrm,bf->at,bf->count,-1);
        rqst->instrm_length += bf->count;          
        bf->count = 0;
................................................................................
      }

    if ( rqst->left > 0 )
      {  
        int L;
        Buffer_Grow_Reserve(bf,bf->count+4*1024);      
        L = Yo_Minu(bf->capacity-bf->count,rqst->left);
        Tcp_Asio_Recv(rqst->sok,bf->at+bf->count,L,L,rqst,Cbk_Httpd_Getting_Postdta);
      }
    else
      {
        Httpd_Perform_Request(rqst);
      }  
    
    return 0;
  }
#endif
  ;
  
void Httpd_Analyze_Qline(char *text,YOYO_HTTPD_REQUEST *rqst)
#ifdef _YOYO_HTTPD_BUILTIN
  {
................................................................................
          }
        S = ++q;
      }
  }
#endif
  ;

int Cbk_Httpd_Getting_Request(void *_rqst, int status, int count)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    int i;
    YOYO_HTTPD_REQUEST *rqst = _rqst;
    YOYO_BUFFER *bf = rqst->bf;

    if ( status == ASIO_TIMER )
      return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_TIMER),0;
    if ( !ASIO_ST_SUCCEEDED(status) )


      return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_IOFAIL),
             Tcp_Close(rqst->sok),0;



    bf->count += count;

    if ( bf->count >= HTTPD_MAX_REQUEST_LENGTH )

      return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_LONGRQST),
             Tcp_Close(rqst->sok),0;



    i = rqst->nline; 
  
  next_line:
    
    while ( i < bf->count && bf->at[i] != '\n' ) ++i;
    
    if ( bf->at[i] != '\n' )
      Tcp_Asio_Recv(rqst->sok,bf->at+bf->count,bf->capacity-bf->count,1,rqst,Cbk_Httpd_Getting_Request);
    else
      {
        if ( !rqst->nline )
          { rqst->nline = ++i; goto next_line; }
        else
          {
            int nonempty = 0;
................................................................................
                  }
                else
                  {
                    int L;
                    rqst->left -= bf->count;
                    Buffer_Grow_Reserve(bf,HTTPD_MAXBUF_POSTDATA_LENGTH);      
                    L = Yo_Minu(bf->capacity-bf->count,rqst->left);
                    Tcp_Asio_Recv(rqst->sok,bf->at+bf->count,L,L,rqst,Cbk_Httpd_Getting_Postdta);
                  }                
              }
            else if ( rqst->method == HTTPD_GET_METHOD 
              || rqst->method == HTTPD_HEAD_METHOD 
              || rqst->method == HTTPD_DELETE_METHOD )
              {
                Httpd_Perform_Request(rqst);
              }
            else

              return rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_BADMETHOD),
                     Tcp_Close(rqst->sok),0;


          }
      }

    return 0;
  }
#endif
  ;
  
int Cbk_Httpd_Accept(void *_httpd,int status,YOYO_TCPSOK *sok)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    YOYO_HTTPD *httpd = _httpd;

    if ( status == ASIO_TIMER )
      return httpd->callback(httpd->obj,0,HTTPD_STAT_TIMER),0;


    if ( !ASIO_ST_SUCCEEDED(status) )
      return httpd->callback(httpd->obj,0,HTTPD_STAT_ACCEPTFAIL),
              0;
    else
      {
        YOYO_HTTPD_REQUEST *rqst;
        Tcp_Asio_Accept(httpd->sok,httpd,Cbk_Httpd_Accept);
        rqst = Httpd_Request(httpd,sok);
        if ( HTTPD_ACCEPT == httpd->callback(httpd->obj,rqst,HTTPD_RQST_CONNECT) )
          Tcp_Asio_Recv(rqst->sok,rqst->bf->at,rqst->bf->capacity,1,rqst,Cbk_Httpd_Getting_Request);
        else
          httpd->callback(httpd->obj,rqst,HTTPD_STAT_REJECTED);
      }

    return 0;
  }
#endif
  ;
  
void Httpd_Listen(YOYO_HTTPD *httpd, char *host, int port)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    httpd->sok = __Refe(Tcp_Listen(TCPSOK_ASYNC,host,port,0));
    free(httpd->host);
    httpd->host = Str_Copy_Npl(host,-1);
    httpd->port = port;
    Tcp_Asio_Accept(httpd->sok,httpd,Cbk_Httpd_Accept);
  }
#endif
  ;
  
void Httpd_Shutdown(YOYO_HTTPD *httpd)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    Tcp_Asio_Shutdown(httpd->sok);
  }
#endif
  ;
  
void YOYO_HTTPD_Destruct(YOYO_HTTPD *httpd)
#ifdef _YOYO_HTTPD_BUILTIN
  {
................................................................................
    __Unrefe(httpd->obj);
    __Unrefe(httpd->sok);
    __Destruct(httpd);
  }
#endif
  ;
  
YOYO_HTTPD *Httpd_Server(void *obj, httpd_callback_t callback)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    YOYO_HTTPD *httpd = __Object_Dtor(sizeof(YOYO_HTTPD),YOYO_HTTPD_Destruct);
    httpd->obj  = __Refe(obj);
    httpd->callback = callback;
    return httpd;
  }
#endif
  ;
  
#endif /* C_once_BE85262D_CDA8_4AF5_B684_8A30EB6D7370 */








<







 







>







 







|



<


<
<
<
>
>
|
|
>
>









|
>













|
>





<









|







 







|


<


<
<
<
>
>
|
|
>
>










|
|
>







 







|





<
<







 







|



<


<
<
<
>
>
|
|
>
>




>
|
|
>
>








|







 







|









>
|
|
>
|


<
<




|


|
|
<
|
>
|
<
<
<



|


|



<
<







|



|







|







 







|












49
50
51
52
53
54
55

56
57
58
59
60
61
62
...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
...
386
387
388
389
390
391
392
393
394
395
396

397
398



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435

436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
...
466
467
468
469
470
471
472
473
474
475

476
477



478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
...
504
505
506
507
508
509
510
511
512
513
514
515
516


517
518
519
520
521
522
523
...
585
586
587
588
589
590
591
592
593
594
595

596
597



598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
...
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671


672
673
674
675
676
677
678
679
680

681
682
683



684
685
686
687
688
689
690
691
692
693


694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
...
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
#include "yoyo.hc"
#include "string.hc"
#include "buffer.hc"
#include "dicto.hc"
#include "file.hc"
#include "tcpip.hc"
#include "url.hc"


#ifdef _LIBYOYO
#define _YOYO_HTTPD_BUILTIN
#endif

struct _YOYO_HTTPD_REQUEST;
typedef int (*httpd_callback_t)(void *obj, struct _YOYO_HTTPD_REQUEST *rqst, int status);
................................................................................
#ifdef _YOYO_HTTPD_BUILTIN
  {
    Httpd_Detach_Request(rqst);
    __Unrefe(rqst->httpd);
    __Unrefe(rqst->sok);
    free(rqst->remote_addr);
    free(rqst->uri);
    free(rqst->referer);
    __Unrefe(rqst->bf);
    __Unrefe(rqst->qhdr);
    __Unrefe(rqst->instrm);
    __Unrefe(rqst->outstrm);
    free(rqst->outstrm_type);
    free(rqst->location);
    free(rqst->cache_control);
................................................................................
            bf->count += L;
          }
      }
  }  
#endif
  ;
  
void Cbk_Httpd_Sending_Result(YOYO_HTTPD_REQUEST *rqst, int error)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    int L;

    YOYO_BUFFER *bf = rqst->bf;




    if ( error )
      {
        rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_IOFAIL);
        Tcp_Close(rqst->sok);
        return;
      }
    
    if ( rqst->outstrm )
      if ( rqst->outstrm_length )
        {
          if ( !rqst->left ) goto finished;
          L = Yo_Minu(rqst->left,bf->capacity);
          L = Oj_Read(rqst->outstrm,bf->at,L,0);
          if ( !L ) goto finished;
          rqst->left -= L;
          Tcp_Aio_Send(rqst->sok,bf->at,L,Cbk_Httpd_Sending_Result,rqst);
          return;
        }
      else /*chunked*/
        {
          int i, j;
          char len[30];
          L = bf->capacity - 32;        
          L = Oj_Read(rqst->outstrm,bf->at+30,L,0);
          sprintf(len,"%x\r\n",L);
          i = strlen(len);
          j = 30-i;
          memcpy(bf->at+j,len,i);
          memcpy(bf->at+30+L,"\r\n",2);
          if ( !L ) { rqst->outstrm_length = -1; rqst->left = 0; }
          Tcp_Aio_Send(rqst->sok,bf->at,L,Cbk_Httpd_Sending_Result,rqst);
          return;
        }
      
  finished:
    rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_FINISHED);
    Tcp_Graceful_Close(rqst->sok);

  }
#endif
  ;
  
void Httpd_Continue_Request(YOYO_HTTPD_REQUEST *rqst, int st)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    YOYO_BUFFER *bf = rqst->bf;
    Httpd_Gen_Response(rqst,st);
    Tcp_Aio_Send(rqst->sok,bf->at,bf->count,Cbk_Httpd_Sending_Result,rqst);
  }
#endif
  ;
  
void Httpd_Perform_Request(YOYO_HTTPD_REQUEST *rqst)
#ifdef _YOYO_HTTPD_BUILTIN
  {
................................................................................
    st = rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_RQST_PERFORM);
    if ( st )
      Httpd_Continue_Request(rqst,st);
  }
#endif
  ;
    
void Cbk_Httpd_Getting_Postdta(YOYO_HTTPD_REQUEST *rqst, int error, int count)
#ifdef _YOYO_HTTPD_BUILTIN
  {

    YOYO_BUFFER *bf = rqst->bf;
    



    if ( error )
      {
        rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_IOFAIL);
        Tcp_Close(rqst->sok);
        return;
      }

    bf->count += count;
    rqst->left -= count;
    
    if ( rqst->instrm || bf->count > HTTPD_MAXBUF_POSTDATA_LENGTH )
      {
        if ( !rqst->instrm ) 
          {
            if ( HTTPD_ACCEPT != rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_RQST_POSTDTA) )
              {
                rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_LONGRQST);
                Tcp_Close(rqst->sok);
                return;
              }
            if ( !rqst->instrm )
              rqst->instrm = __Refe(Cfile_Temp());
          }
        Oj_Write(rqst->instrm,bf->at,bf->count,-1);
        rqst->instrm_length += bf->count;          
        bf->count = 0;
................................................................................
      }

    if ( rqst->left > 0 )
      {  
        int L;
        Buffer_Grow_Reserve(bf,bf->count+4*1024);      
        L = Yo_Minu(bf->capacity-bf->count,rqst->left);
        Tcp_Aio_Recv(rqst->sok,bf->at+bf->count,L,L,Cbk_Httpd_Getting_Postdta,rqst);
      }
    else
      {
        Httpd_Perform_Request(rqst);
      }  


  }
#endif
  ;
  
void Httpd_Analyze_Qline(char *text,YOYO_HTTPD_REQUEST *rqst)
#ifdef _YOYO_HTTPD_BUILTIN
  {
................................................................................
          }
        S = ++q;
      }
  }
#endif
  ;

void Cbk_Httpd_Getting_Request(YOYO_HTTPD_REQUEST *rqst, int error, int count)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    int i;

    YOYO_BUFFER *bf = rqst->bf;




    if ( error )
      {
        rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_IOFAIL);
        Tcp_Close(rqst->sok);
        return;
      }

    bf->count += count;

    if ( bf->count >= HTTPD_MAX_REQUEST_LENGTH )
      {
        rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_LONGRQST);
        Tcp_Close(rqst->sok);
        return;
      }

    i = rqst->nline; 
  
  next_line:
    
    while ( i < bf->count && bf->at[i] != '\n' ) ++i;
    
    if ( bf->at[i] != '\n' )
      Tcp_Aio_Recv(rqst->sok,bf->at+bf->count,bf->capacity-bf->count,1,Cbk_Httpd_Getting_Request,rqst);
    else
      {
        if ( !rqst->nline )
          { rqst->nline = ++i; goto next_line; }
        else
          {
            int nonempty = 0;
................................................................................
                  }
                else
                  {
                    int L;
                    rqst->left -= bf->count;
                    Buffer_Grow_Reserve(bf,HTTPD_MAXBUF_POSTDATA_LENGTH);      
                    L = Yo_Minu(bf->capacity-bf->count,rqst->left);
                    Tcp_Aio_Recv(rqst->sok,bf->at+bf->count,L,L,Cbk_Httpd_Getting_Postdta,rqst);
                  }                
              }
            else if ( rqst->method == HTTPD_GET_METHOD 
              || rqst->method == HTTPD_HEAD_METHOD 
              || rqst->method == HTTPD_DELETE_METHOD )
              {
                Httpd_Perform_Request(rqst);
              }
            else
              {
                rqst->httpd->callback(rqst->httpd->obj,rqst,HTTPD_STAT_BADMETHOD);
                Tcp_Close(rqst->sok);
                return;
              }
          }
      }


  }
#endif
  ;
  
void Cbk_Httpd_Accept(YOYO_HTTPD *httpd,int error,YOYO_TCPSOK *sok)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    if ( error )
      {

        httpd->callback(httpd->obj,0,HTTPD_STAT_ACCEPTFAIL);
        return;
      }



    else
      {
        YOYO_HTTPD_REQUEST *rqst;
        Tcp_Aio_Accept(httpd->sok,Cbk_Httpd_Accept,httpd);
        rqst = Httpd_Request(httpd,sok);
        if ( HTTPD_ACCEPT == httpd->callback(httpd->obj,rqst,HTTPD_RQST_CONNECT) )
          Tcp_Aio_Recv(rqst->sok,rqst->bf->at,rqst->bf->capacity,1,Cbk_Httpd_Getting_Request,rqst);
        else
          httpd->callback(httpd->obj,rqst,HTTPD_STAT_REJECTED);
      }


  }
#endif
  ;
  
void Httpd_Listen(YOYO_HTTPD *httpd, char *host, int port)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    httpd->sok = __Refe(Tcp_Listen(host,port,0));
    free(httpd->host);
    httpd->host = Str_Copy_Npl(host,-1);
    httpd->port = port;
    Tcp_Aio_Accept(httpd->sok,Cbk_Httpd_Accept,httpd);
  }
#endif
  ;
  
void Httpd_Shutdown(YOYO_HTTPD *httpd)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    Tcp_Shutdown(httpd->sok);
  }
#endif
  ;
  
void YOYO_HTTPD_Destruct(YOYO_HTTPD *httpd)
#ifdef _YOYO_HTTPD_BUILTIN
  {
................................................................................
    __Unrefe(httpd->obj);
    __Unrefe(httpd->sok);
    __Destruct(httpd);
  }
#endif
  ;
  
YOYO_HTTPD *Httpd_Server(httpd_callback_t callback,void *obj)
#ifdef _YOYO_HTTPD_BUILTIN
  {
    YOYO_HTTPD *httpd = __Object_Dtor(sizeof(YOYO_HTTPD),YOYO_HTTPD_Destruct);
    httpd->obj  = __Refe(obj);
    httpd->callback = callback;
    return httpd;
  }
#endif
  ;
  
#endif /* C_once_BE85262D_CDA8_4AF5_B684_8A30EB6D7370 */

Changes to httpx.hc.

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

378
379
380
381

382

383
384
385
386
387
388

389
390
391

392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410

411
412
413
414
415


416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

499
500


501
502
503
504
505
506

507

508
509
510
511
512
513
514
515
516
517
518

519
520
521


522
523
524
525
526
527
528
529
530
531
532
533

534
535
536

537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587

588
589
590
591
592

593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621


622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654

655
656

657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740

741

742

743
744
745
746
747
748
749
750
751
752
753
754
755
...
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
...
805
806
807
808
809
810
811













812
813
814
815
816
817
818
819
820
821
822
823

824
825
826
827
828
829
830
...
841
842
843
844
845
846
847
848

849
850
851
852
853
854
855
...
866
867
868
869
870
871
872
873

874
875
876
877
878
879
880
#include "yoyo.hc"
#include "string.hc"
#include "buffer.hc"
#include "dicto.hc"
#include "file.hc"
#include "tcpip.hc"
#include "url.hc"
#include "asio.hc"

#ifdef _LIBYOYO
#define _HTTPX_BUILTIN
#endif

typedef void (*httpx_collback_t)(void *obj, struct _YOYO_HTTPX *httpx, int status);

................................................................................
    HTTPX_GETTING_CONTENT         = 0x00000f40,
    HTTPX_FINISHED                = 0x00000f41,
    HTTPX_SEND                    = 0x00000e01,
    HTTPX_RECV                    = 0x00000e02,

    HTTPX_INVALID_RESPONSE        = 0x00000d01,
    HTTPX_INVALID_RESPONSE_CODE   = 0x00000d02,

    HTTPX_CONTINUE                = -1,
  };

#define HTTPX_SUCCEEDED(Status) (((Status)&0x8f000000) == 0)
#define HTTPX_STATUS(Status)    ((Status)&0x0fff)

int Httpx_Asio_Recv(YOYO_HTTPX *httpx, void *dta, int count, int mincount, asio_recv_callback_t callback)
#ifdef _HTTPX_BUILTIN
  {
    if ( !httpx->ssl )
      return Tcp_Asio_Recv(httpx->netchnl,dta,count,mincount,httpx,callback);
    return 0;
  }
#endif
  ;
  
int Httpx_Asio_Send(YOYO_HTTPX *httpx, void *dta, int count, asio_send_callback_t callback)
#ifdef _HTTPX_BUILTIN
  {
    if ( !httpx->ssl )
      return Tcp_Asio_Send(httpx->netchnl,dta,count,httpx,callback);
    return 0;
  }
#endif
  ;
  
void Httpx_Append_Header_Line(YOYO_BUFFER *bf, char *name, char *value)
#ifdef _HTTPX_BUILTIN
  {
................................................................................
  }
#endif
  ;

void Httpx_Interrupt(YOYO_HTTPX *httpx)
#ifdef _HTTPX_BUILTIN
  {
    if ( !httpx->ssl )
      Tcp_Asio_Interrupt(httpx->netchnl);
    STRICT_REQUIRE( httpx->interrupted == 1 );
  }
#endif
  ;
    
void Httpx_Do_Callback(YOYO_HTTPX *httpx, int status)
#ifdef _HTTPX_BUILTIN
  {
    if ( status & HTTPX_INTERRUPTED ) /* Asio interrupt callback fall here */
      httpx->interrupted = 1;
         
    if ( httpx->mon_callback )
      httpx->mon_callback(httpx->mon_obj,httpx,httpx->state|status);

    if ( ( httpx->interrupted || !HTTPX_SUCCEEDED(status) )
      || ( httpx->state == HTTPX_FINISHED && !httpx->keepalive ) )
      {
        Oj_Close(httpx->netchnl); 
        httpx->keepalive = 0;
      }
  }
#endif
  ;
  
void Httpx_Timer_Callback(YOYO_HTTPX *httpx)
#ifdef _HTTPX_BUILTIN
  {
    if ( httpx->mon_callback )
      httpx->mon_callback(httpx->mon_obj,httpx,httpx->state|HTTPX_TIMER);    
  }
#endif
  ;

int Httpx_Update_Until_EOH(YOYO_HTTPX *httpx, int count)
#ifdef _HTTPX_BUILTIN
  {
................................................................................
          }
        S = ++q;
      }
  }
#endif
  ;
  
int Cbk_Httpx_Getting_Content(void *_httpx, int status, int count)
#ifdef _HTTPX_BUILTIN
  {
    int L;
    YOYO_HTTPX *httpx = _httpx;
    YOYO_BUFFER *bf = httpx->bf;
    
    if ( status == ASIO_TIMER )
      return Httpx_Timer_Callback(httpx),0;


    if ( !ASIO_ST_SUCCEEDED(status) )
      return Httpx_Do_Callback(httpx,HTTPX_BROKEN|(ASIO_ST_INTERRUPTED(status)?HTTPX_INTERRUPTED:0)),
             httpx->state;



    L = Yo_MIN(httpx->left,count);
    httpx->left -= L;
    httpx->streamed += L;
    Oj_Write(httpx->outstrm,bf->at,L,-1);

    if ( !httpx->left )

      return httpx->state = HTTPX_FINISHED,
             Httpx_Do_Callback(httpx,0),
             httpx->state;


    if ( status&ASIO_SYNCHRONOUS )
      return HTTPX_CONTINUE;
    
    return Httpx_Asio_Recv(httpx, bf->at, bf->capacity, Yo_MIN(httpx->left,bf->capacity)
                          ,Cbk_Httpx_Getting_Content);
  }
#endif
  ;

int Cbk_Http_Getting_Chunked(void *_httpx, int status, int count)
#ifdef _HTTPX_BUILTIN
  {
    YOYO_HTTPX *httpx = _httpx;
    YOYO_BUFFER *bf = httpx->bf;
    int iterate = 0;
    
    if ( status == ASIO_TIMER )
      return Httpx_Timer_Callback(httpx),0;


    httpx->state = HTTPX_GETTING_CONTENT;
    if ( !ASIO_ST_SUCCEEDED(status) )
      return Httpx_Do_Callback(httpx,HTTPX_BROKEN|(ASIO_ST_INTERRUPTED(status)?HTTPX_INTERRUPTED:0)),
             httpx->state;


  
    bf->count += count;
  
    if ( status & ASIO_SYNCHRONOUS )
      return HTTPX_CONTINUE;
  
    if ( httpx->outstrm ) for (;;)
      {
        if ( httpx->left )
          {
            int L = Yo_Minu(httpx->left,bf->count-httpx->nline);
            Oj_Write(httpx->outstrm,bf->at+httpx->nline,L,L);
            httpx->left -= L;
            if ( httpx->left )
              {
                bf->count = 0;
                httpx->nline = 0;
                if ( (status = Httpx_Asio_Recv(httpx,bf->at,bf->capacity,Yo_Minu(httpx->left,bf->capacity)
                                            ,Cbk_Http_Getting_Chunked)) 
                             != HTTPX_CONTINUE )
                    return status;
              }
            else
              {
                httpx->nline += L;
              }
          }
        else
................................................................................
                    httpx->left = strtol(q+httpx->nline,&e,16);
                    if ( !httpx->left && *(q+httpx->nline) == '0' )
                      {
                        /* fixme */
                        if ( q[i] != '\n' && !(q[i] == '\r' && q[i+1] == '\n' ) )
                          {
                            Buffer_Grow_Reserve(bf,bf->count+2);
                            if ( (status = Httpx_Asio_Recv(httpx,bf->at+bf->count,2,1
                                                         ,Cbk_Http_Getting_Chunked)) 
                                         != HTTPX_CONTINUE )
                            continue;
                          }
                        break; // finish
                      }
                    httpx->nline = i;
                  }
              }
            else  
              {
                Buffer_Grow_Reserve(bf,bf->count+128);
                if ( (status = Httpx_Asio_Recv(httpx,bf->at+bf->count,128,1
                                               ,Cbk_Http_Getting_Chunked)) 
                               != HTTPX_CONTINUE )
                  return status;
              } 
          }
      }

    return httpx->state = HTTPX_FINISHED,
           Httpx_Do_Callback(httpx,0),
           httpx->state;
  }
#endif
  ;
    
int Cbk_Httpx_Getting_Headers(void *_httpx, int status, int count)
#ifdef _HTTPX_BUILTIN
  {
    YOYO_HTTPX *httpx = _httpx;
    YOYO_BUFFER *bf = httpx->bf;
    int iterate = 0;

    
    if ( status == ASIO_TIMER )


      return Httpx_Timer_Callback(httpx),0;

    httpx->state = HTTPX_GETTING_HEADERS;
    if ( !ASIO_ST_SUCCEEDED(status) )
      return Httpx_Do_Callback(httpx,HTTPX_BROKEN|(ASIO_ST_INTERRUPTED(status)?HTTPX_INTERRUPTED:0)),
             httpx->state;

    

    if ( httpx->bf->count == 0 )
      {
        if ( !strncmp_I(bf->at,"HTTP/1.",7) )
          {
            char *q = bf->at + 8, *Q;
            bf->at[count] = 0;
            while ( *q && !Isspace(*q) ) ++q;
            while ( Isspace(*q) ) ++q;
            httpx->status = strtol(q,&q,10);
            
            if ( httpx->status < 100 || httpx->status >= 510 )

              return  httpx->state = HTTPX_INVALID_RESPONSE_CODE,
                      Httpx_Do_Callback(httpx,HTTPX_BROKEN),
                      httpx->state;


                          
            while ( *q != '\n' && *q != '\r' && Isspace(*q) ) ++q;
            Q = q;
            while ( *q && *q != '\n' && *q != '\r' && !Isspace(*q) ) ++q;
            httpx->status_text = Str_Range_Npl(Q,q);
            bf->count = (q - bf->at);         
            count -= bf->count; 
            httpx->nline = 0;
            __Unrefe(httpx->hdrs);
            httpx->hdrs = __Refe(Dicto_Ptrs());
          }
        else

          return  httpx->state = HTTPX_INVALID_RESPONSE,
                  Httpx_Do_Callback(httpx,HTTPX_BROKEN),
                  httpx->state;

      }
    else
      iterate = status&ASIO_SYNCHRONOUS;
      
    for(;;) 
      {
        int eoh = Httpx_Update_Until_EOH(httpx,count);

        if ( eoh )
          {
            char *foo;
            Httpx_Analyze_Headers(httpx);
            httpx->left = 0;
            
            if ( foo = Dicto_Get(httpx->hdrs,"Connection",0) )
              {
                if ( !strcmp_I(foo,"Keep-Alive") )
                  httpx->keepalive = 1;
              }

            if ( foo = Dicto_Get(httpx->hdrs,"Content-Length",0) )
              {
                httpx->left = Yo_Minu(Str_To_Int(foo),httpx->maxcount);
              }
            else if ( strcmp_I(Dicto_Get(httpx->hdrs,"Transfer-Encoding",""),"chunked") == 0 )
              {
                httpx->chunked = 1;  
                httpx->nline = 0;
              }
              
            if ( httpx->outstrm && httpx->left != 0 )
              {
                int L = bf->count-eoh;
                L = Yo_MIN(httpx->left,L);
                httpx->left -= L;
                Oj_Write(httpx->outstrm,bf->at+eoh,L,-1);
                httpx->streamed += L;
                bf->count = 0;
                while ( httpx->left )
                  {
                    status = Httpx_Asio_Recv(httpx,bf->at,bf->capacity,Yo_MIN(httpx->left,bf->capacity)
                                            ,Cbk_Httpx_Getting_Content);
                    if ( status != HTTPX_CONTINUE )
                      return status;
                  }
              }
            else if ( httpx->chunked )
              {
                httpx->nline = eoh;
                httpx->left = 0;
                return Cbk_Http_Getting_Chunked(httpx,0,0);

              }
            
            return httpx->state = HTTPX_FINISHED,
                   Httpx_Do_Callback(httpx,0),
                   httpx->state;

          }
        
        if ( iterate )
           return HTTPX_CONTINUE;
           
        Buffer_Grow_Reserve(bf,bf->count + 512);
        
        status = Httpx_Asio_Recv(httpx, bf->at+bf->count, 512, 1
                                ,Cbk_Httpx_Getting_Headers);    

        if ( status != HTTPX_CONTINUE )
          return status;
      }
  }
#endif
  ;
  
int Cbk_Httpx_Requested(void *_httpx, int status)
#ifdef _HTTPX_BUILTIN
  {
    YOYO_HTTPX *httpx = _httpx;

    if ( status == ASIO_TIMER )
      return Httpx_Timer_Callback(httpx),0;

    httpx->state = HTTPX_REQUESTED;
    if ( !ASIO_ST_SUCCEEDED(status) )
      return Httpx_Do_Callback(httpx,HTTPX_BROKEN|(ASIO_ST_INTERRUPTED(status)?HTTPX_INTERRUPTED:0)),
             httpx->state;



    Httpx_Do_Callback(httpx,HTTPX_REQUESTED);
    Buffer_Grow_Reserve(httpx->bf,1023);
    httpx->bf->count = 0;
    httpx->keepalive = 0;
    
    return Httpx_Asio_Recv(httpx, httpx->bf->at, 1023, 12 /* lengthof HTTP/1.1 200 */
                          ,Cbk_Httpx_Getting_Headers);    
  }
#endif
  ;
  
int Cbk_Httpx_Post(void *_httpx, int status)
#ifdef _HTTPX_BUILTIN
  {
    YOYO_HTTPX *httpx = _httpx;
    YOYO_BUFFER *bf = httpx->bf;
    int i;

    if ( status == ASIO_TIMER )
      return Httpx_Timer_Callback(httpx),0;

    if ( httpx->state == HTTPX_SENDING_POSTDATA && (status & ASIO_SYNCHRONOUS) )
      return HTTPX_CONTINUE;

    if ( httpx->state != HTTPX_SENDING_POSTDATA )
      {
        bf->count = 0;
        httpx->left = httpx->poststrm?Oj_Available(httpx->poststrm):0;
      }

    httpx->state = HTTPX_SENDING_POSTDATA;
    if ( !ASIO_ST_SUCCEEDED(status) )

      return Httpx_Do_Callback(httpx,HTTPX_BROKEN|(ASIO_ST_INTERRUPTED(status)?HTTPX_INTERRUPTED:0)),
             httpx->state;

    
    for ( ;; )
      {
        bf->count = 0;
        i = !httpx->left ? 0 : Oj_Read(httpx->poststrm,bf->at,Yo_MIN(httpx->left,bf->capacity),-1);
        httpx->left -= i;
        if ( !Httpx_Asio_Send(httpx, bf->at, i,
                              httpx->left ? Cbk_Httpx_Post : Cbk_Httpx_Requested) )
        return 0;
      }
  }
#endif
  ;
    
int Cbk_Httpx_Connected(void *_httpx,int status)
#ifdef _HTTPX_BUILTIN
  {
    YOYO_HTTPX *httpx = _httpx;

    if ( status == ASIO_TIMER )
      return Httpx_Timer_Callback(httpx),0;

    httpx->state = HTTPX_CONNECTED;
    if ( !ASIO_ST_SUCCEEDED(status) )
      {
        Httpx_Do_Callback(httpx,HTTPX_BROKEN
                                     |(ASIO_ST_INTERRUPTED(status)?HTTPX_INTERRUPTED:0)
                                     |(ASIO_ST_PERMANENT(status)?HTTPX_PERMANENT_ERROR:0));
        return httpx->state;
      }
      
    Httpx_Do_Callback(httpx,HTTPX_CONNECTED);
    
    /* httpx->bf contains prepared request */
    return Httpx_Asio_Send(httpx, httpx->bf->at, httpx->bf->count,
                           (httpx->method == HTTPX_POST || httpx->method == HTTPX_PUT ) 
                                ?Cbk_Httpx_Post
                                :Cbk_Httpx_Requested);    
  }
#endif
  ;
  
int Cbk_Httpx_Proxy_Connected(void *_httpx,int status)
#ifdef _HTTPX_BUILTIN
  {
    YOYO_HTTPX *httpx = _httpx;

    if ( status == ASIO_TIMER )
      return Httpx_Timer_Callback(httpx),0;
      
    httpx->state = HTTPX_PROXY_CONNECTED;
    if ( !ASIO_ST_SUCCEEDED(status) )
      {
        Httpx_Do_Callback(httpx,HTTPX_BROKEN
                                |(ASIO_ST_INTERRUPTED(status)?HTTPX_INTERRUPTED:0)
                                |(ASIO_ST_PERMANENT(status)?HTTPX_PERMANENT_ERROR:0));
        return httpx->state;
      }
      
    Httpx_Do_Callback(httpx,HTTPX_PROXY_CONNECTED);
    
    /// auth / ssl connect
    return Cbk_Httpx_Connected(_httpx,status);
  }
#endif
  ;
  
int Httpx_Asio_Connect(YOYO_HTTPX *httpx)
#ifdef _HTTPX_BUILTIN
  {
    if ( httpx->keepalive && httpx->netchnl )
      {
        return Httpx_Asio_Send(httpx, httpx->bf->at, httpx->bf->count,
                     (httpx->method == HTTPX_POST || httpx->method == HTTPX_PUT) 
                          ?Cbk_Httpx_Post
                          :Cbk_Httpx_Requested);    
      }
    else
      { 
        __Unrefe(httpx->netchnl);
        httpx->netchnl = __Refe(Tcp_Socket(httpx->async?TCPSOK_ASYNC:0));
        
        if ( httpx->proxy_url )
          return Tcp_Asio_Connect(httpx->netchnl,httpx->proxy_url->host,httpx->proxy_url->port,httpx,Cbk_Httpx_Proxy_Connected);

          

        return Tcp_Asio_Connect(httpx->netchnl,httpx->url->host,httpx->url->port,httpx,Cbk_Httpx_Connected);

      }
  }
#endif
  ;
  
int Httpx_Query(YOYO_HTTPX *httpx, int method, char *uri, YOYO_DICTO *hdrs, void *poststrm, void *contstrm, int maxcount)
#ifdef _HTTPX_BUILTIN
  {
    if ( httpx->status_text ) { free(httpx->status_text); httpx->status_text = 0; }
    httpx->interrupted = 0;
    httpx->status = 0;
    httpx->method = method;
    httpx->maxcount = maxcount?maxcount:INT_MAX;
................................................................................
    
    if ( !uri ) 
      uri = httpx->url->uri;
    else if ( uri[0] != '/' )
      uri = Str_Join_2('/',httpx->url->uri,uri);
    
    Build_Http_Request(httpx,method,uri,hdrs);
    if ( 0 == Httpx_Asio_Connect(httpx) )
      return 1;
    else
      return httpx->state == HTTPX_FINISHED; 
  }
#endif
  ;
  
#define Httpx_Client(Url,Flags) Httpx_Client_Callback(Url,Flags,0,0)
YOYO_HTTPX *Httpx_Client_Callback(char *url,int flags, httpx_collback_t callback, void *cbkobj)
#ifdef _HTTPX_BUILTIN
................................................................................
      }

    return httpx;
  }
#endif
  ;














int Httpx_Head(YOYO_HTTPX *httpx, char *uri)
#ifdef _HTTPX_BUILTIN
  {
    int ret;
    __Auto_Release
      {
        if ( !httpx ) 
          {
            httpx = Httpx_Client(uri,0);
            uri = 0;
          }
        ret = Httpx_Query(httpx,HTTPX_GET,uri,0,0,0,0);

      }
    return ret;
  }
#endif
  ;
  
int Httpx_Get(YOYO_HTTPX *httpx, char *uri, YOYO_DICTO *params, void *contstrm, int maxcount)
................................................................................
            uri = 0;
          }
        else
          {
            if ( uri && params )
              uri = Url_Compose(uri,params);
          }
        ret = Httpx_Query(httpx,HTTPX_GET,uri,0,0,contstrm,maxcount);

      }
    return ret;
  }
#endif
  ;
  
int Httpx_Post(YOYO_HTTPX *httpx, char *uri, YOYO_DICTO *params, void *contstrm, int maxcount)
................................................................................
          }
        if ( params ) 
          {
            char *encoded = Url_Xform_Encode(params);
            if ( encoded )
              poststrm = Memory_As_File(encoded,strlen(encoded));
          }
        ret = Httpx_Query(httpx,HTTPX_POST,uri,0,poststrm,contstrm,maxcount);

      }
    return ret;
  }
#endif
  ;
  
int Httpx_Content_Length(YOYO_HTTPX *httpx)







|







 







<
<





|



|
<




|



|
<







 







|
|
|







<
<
<









|
|
|
|
|
|
|
<
<







 







|



<

|
<
<
>
|
<
|
<
>
|
>






>
|
|
<
>
|
<
<
|
|





|


<


|
<
<
>
|
<
<
|
<
>
>



<
<
<











|
|
<
|







 







|
|
<
<









|
<
<
|




|
|
<




|


<

<
>

<
>
>
|
|
<
<
|
<
>
|
>











>
|
|
<
>
>












>
|
|
<
>
|
<
<
|
<
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
>
|
|
|
|
<
>
|
|
<
<
<
|
<
|
<
<
<
<
<




|


|

|
<
|
<
<
|
<
>
>






|





|


<



<
<
<
<
<
<







|
>
|
<
>
|
<
|
|
|
|
|
|
<
<




|


|

|
<
|
<
<
<

<
|
|





|







|


|

|
<
|
<
<
<

<
|
|





|




|




|







|


|
>

>
|
>





|







 







|
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>











|
>







 







|
>







 







|
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
143
144
145
146
147
148
149


150
151
152
153
154
155
156
157
158
159

160
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299


300
301
302
303
304
305
306
...
353
354
355
356
357
358
359
360
361
362
363

364
365


366
367

368

369
370
371
372
373
374
375
376
377
378
379
380

381
382


383
384
385
386
387
388
389
390
391
392

393
394
395


396
397


398

399
400
401
402
403



404
405
406
407
408
409
410
411
412
413
414
415
416

417
418
419
420
421
422
423
424
...
439
440
441
442
443
444
445
446
447


448
449
450
451
452
453
454
455
456
457


458
459
460
461
462
463
464

465
466
467
468
469
470
471

472

473
474

475
476
477
478


479

480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496

497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513

514
515


516

517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553

554
555
556
557
558
559
560
561
562
563
564
565
566

567
568
569



570

571





572
573
574
575
576
577
578
579
580
581

582


583

584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

601
602
603






604
605
606
607
608
609
610
611
612
613

614
615

616
617
618
619
620
621


622
623
624
625
626
627
628
629
630
631

632



633

634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654

655



656

657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
...
713
714
715
716
717
718
719
720



721
722
723
724
725
726
727
...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
...
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
#include "yoyo.hc"
#include "string.hc"
#include "buffer.hc"
#include "dicto.hc"
#include "file.hc"
#include "tcpip.hc"
#include "url.hc"
#include "tasque.hc"

#ifdef _LIBYOYO
#define _HTTPX_BUILTIN
#endif

typedef void (*httpx_collback_t)(void *obj, struct _YOYO_HTTPX *httpx, int status);

................................................................................
    HTTPX_GETTING_CONTENT         = 0x00000f40,
    HTTPX_FINISHED                = 0x00000f41,
    HTTPX_SEND                    = 0x00000e01,
    HTTPX_RECV                    = 0x00000e02,

    HTTPX_INVALID_RESPONSE        = 0x00000d01,
    HTTPX_INVALID_RESPONSE_CODE   = 0x00000d02,


  };

#define HTTPX_SUCCEEDED(Status) (((Status)&0x8f000000) == 0)
#define HTTPX_STATUS(Status)    ((Status)&0x0fff)

void Httpx_Aio_Recv(YOYO_HTTPX *httpx, void *dta, int count, int mincount, tcp_recv_callback_t callback)
#ifdef _HTTPX_BUILTIN
  {
    if ( !httpx->ssl )
      Tcp_Aio_Recv(httpx->netchnl,dta,count,mincount,callback,httpx);

  }
#endif
  ;
  
void Httpx_Aio_Send(YOYO_HTTPX *httpx, void *dta, int count, tcp_send_callback_t callback)
#ifdef _HTTPX_BUILTIN
  {
    if ( !httpx->ssl )
      Tcp_Aio_Send(httpx->netchnl,dta,count,callback,httpx);

  }
#endif
  ;
  
void Httpx_Append_Header_Line(YOYO_BUFFER *bf, char *name, char *value)
#ifdef _HTTPX_BUILTIN
  {
................................................................................
  }
#endif
  ;

void Httpx_Interrupt(YOYO_HTTPX *httpx)
#ifdef _HTTPX_BUILTIN
  {
    httpx->interrupted = 1;
    if ( !httpx->ssl )
      Tcp_Close(httpx->netchnl);
  }
#endif
  ;
    
void Httpx_Do_Callback(YOYO_HTTPX *httpx, int status)
#ifdef _HTTPX_BUILTIN
  {



    if ( httpx->mon_callback )
      httpx->mon_callback(httpx->mon_obj,httpx,httpx->state|status);

    if ( ( httpx->interrupted || !HTTPX_SUCCEEDED(status) )
      || ( httpx->state == HTTPX_FINISHED && !httpx->keepalive ) )
      {
        Oj_Close(httpx->netchnl); 
        httpx->keepalive = 0;
      }
      
    if ( !HTTPX_SUCCEEDED(status) )
      {
        httpx->state |= HTTPX_BROKEN;
        if ( httpx->interrupted )
          httpx->state |= HTTPX_INTERRUPTED;
      }


  }
#endif
  ;

int Httpx_Update_Until_EOH(YOYO_HTTPX *httpx, int count)
#ifdef _HTTPX_BUILTIN
  {
................................................................................
          }
        S = ++q;
      }
  }
#endif
  ;
  
void Cbk_Httpx_Getting_Content(YOYO_HTTPX *httpx, int error, int count)
#ifdef _HTTPX_BUILTIN
  {
    int L;

    YOYO_BUFFER *bf = httpx->bf;



    if ( error )
      {

        Httpx_Do_Callback(httpx,HTTPX_BROKEN);

        return;
      }
      
    L = Yo_MIN(httpx->left,count);
    httpx->left -= L;
    httpx->streamed += L;
    Oj_Write(httpx->outstrm,bf->at,L,-1);

    if ( !httpx->left )
      {
        httpx->state = HTTPX_FINISHED;
        Httpx_Do_Callback(httpx,0);

        return;
      }



    Httpx_Aio_Recv(httpx, bf->at, bf->capacity, Yo_MIN(httpx->left,bf->capacity)
                          ,Cbk_Httpx_Getting_Content);
  }
#endif
  ;

void Cbk_Http_Getting_Chunked(YOYO_HTTPX *httpx, int error, int count)
#ifdef _HTTPX_BUILTIN
  {

    YOYO_BUFFER *bf = httpx->bf;
    int iterate = 0;



    if ( error )
      {


        Httpx_Do_Callback(httpx,HTTPX_BROKEN);

        return;
      }
  
    bf->count += count;
  



    if ( httpx->outstrm ) for (;;)
      {
        if ( httpx->left )
          {
            int L = Yo_Minu(httpx->left,bf->count-httpx->nline);
            Oj_Write(httpx->outstrm,bf->at+httpx->nline,L,L);
            httpx->left -= L;
            if ( httpx->left )
              {
                bf->count = 0;
                httpx->nline = 0;
                Httpx_Aio_Recv(httpx,bf->at,bf->capacity,Yo_Minu(httpx->left,bf->capacity)
                                            ,Cbk_Http_Getting_Chunked); 

                return;
              }
            else
              {
                httpx->nline += L;
              }
          }
        else
................................................................................
                    httpx->left = strtol(q+httpx->nline,&e,16);
                    if ( !httpx->left && *(q+httpx->nline) == '0' )
                      {
                        /* fixme */
                        if ( q[i] != '\n' && !(q[i] == '\r' && q[i+1] == '\n' ) )
                          {
                            Buffer_Grow_Reserve(bf,bf->count+2);
                            Httpx_Aio_Recv(httpx,bf->at+bf->count,2,1,Cbk_Http_Getting_Chunked);
                            return;


                          }
                        break; // finish
                      }
                    httpx->nline = i;
                  }
              }
            else  
              {
                Buffer_Grow_Reserve(bf,bf->count+128);
                Httpx_Aio_Recv(httpx,bf->at+bf->count,128,1,Cbk_Http_Getting_Chunked); 


                return;
              } 
          }
      }

    httpx->state = HTTPX_FINISHED;
    Httpx_Do_Callback(httpx,0);  

  }
#endif
  ;
    
void Cbk_Httpx_Getting_Headers(YOYO_HTTPX *httpx, int error, int count)
#ifdef _HTTPX_BUILTIN
  {

    YOYO_BUFFER *bf = httpx->bf;

    int eoh;
    

    httpx->state = HTTPX_GETTING_HEADERS;
    
    if ( error )
      {


        Httpx_Do_Callback(httpx,HTTPX_BROKEN);

        return;
      }
      
    if ( httpx->bf->count == 0 )
      {
        if ( !strncmp_I(bf->at,"HTTP/1.",7) )
          {
            char *q = bf->at + 8, *Q;
            bf->at[count] = 0;
            while ( *q && !Isspace(*q) ) ++q;
            while ( Isspace(*q) ) ++q;
            httpx->status = strtol(q,&q,10);
            
            if ( httpx->status < 100 || httpx->status >= 510 )
              {
                httpx->state = HTTPX_INVALID_RESPONSE_CODE;
                Httpx_Do_Callback(httpx,HTTPX_BROKEN);

                return;
              }
                          
            while ( *q != '\n' && *q != '\r' && Isspace(*q) ) ++q;
            Q = q;
            while ( *q && *q != '\n' && *q != '\r' && !Isspace(*q) ) ++q;
            httpx->status_text = Str_Range_Npl(Q,q);
            bf->count = (q - bf->at);         
            count -= bf->count; 
            httpx->nline = 0;
            __Unrefe(httpx->hdrs);
            httpx->hdrs = __Refe(Dicto_Ptrs());
          }
        else
          {
            httpx->state = HTTPX_INVALID_RESPONSE;
            Httpx_Do_Callback(httpx,HTTPX_BROKEN);

            return;
          }


      }

      
    eoh = Httpx_Update_Until_EOH(httpx,count);

    if ( eoh )
      {
        char *foo;
        Httpx_Analyze_Headers(httpx);
        httpx->left = 0;
        
        if ( foo = Dicto_Get(httpx->hdrs,"Connection",0) )
          {
            if ( !strcmp_I(foo,"Keep-Alive") )
              httpx->keepalive = 1;
          }

        if ( foo = Dicto_Get(httpx->hdrs,"Content-Length",0) )
          {
            httpx->left = Yo_Minu(Str_To_Int(foo),httpx->maxcount);
          }
        else if ( strcmp_I(Dicto_Get(httpx->hdrs,"Transfer-Encoding",""),"chunked") == 0 )
          {
            httpx->chunked = 1;  
            httpx->nline = 0;
          }
          
        if ( httpx->outstrm && httpx->left != 0 )
          {
            int L = bf->count-eoh;
            L = Yo_MIN(httpx->left,L);
            httpx->left -= L;
            Oj_Write(httpx->outstrm,bf->at+eoh,L,-1);
            httpx->streamed += L;
            bf->count = 0;
            if ( httpx->left )
              {
                Httpx_Aio_Recv(httpx,bf->at,bf->capacity,Yo_MIN(httpx->left,bf->capacity)
                                        ,Cbk_Httpx_Getting_Content);

                return;
              }
          }
        else if ( httpx->chunked )
          {
            httpx->nline = eoh;
            httpx->left = 0;
            Cbk_Http_Getting_Chunked(httpx,0,0);
            return;
          }
        
        httpx->state = HTTPX_FINISHED;
        Httpx_Do_Callback(httpx,0);

        return;
      }
    



    Buffer_Grow_Reserve(bf,bf->count + 512);

    Httpx_Aio_Recv(httpx, bf->at+bf->count, 512, 1, Cbk_Httpx_Getting_Headers);    





  }
#endif
  ;
  
void Cbk_Httpx_Requested(YOYO_HTTPX *httpx, int error)
#ifdef _HTTPX_BUILTIN
  {
    httpx->state = HTTPX_REQUESTED;

    if ( error )

      {


        Httpx_Do_Callback(httpx,HTTPX_BROKEN);

        return;
      }

    Httpx_Do_Callback(httpx,HTTPX_REQUESTED);
    Buffer_Grow_Reserve(httpx->bf,1023);
    httpx->bf->count = 0;
    httpx->keepalive = 0;
    
    Httpx_Aio_Recv(httpx, httpx->bf->at, 1023, 12 /* lengthof HTTP/1.1 200 */
                          ,Cbk_Httpx_Getting_Headers);    
  }
#endif
  ;
  
void Cbk_Httpx_Post(YOYO_HTTPX *httpx, int error)
#ifdef _HTTPX_BUILTIN
  {

    YOYO_BUFFER *bf = httpx->bf;
    int i;







    if ( httpx->state != HTTPX_SENDING_POSTDATA )
      {
        bf->count = 0;
        httpx->left = httpx->poststrm?Oj_Available(httpx->poststrm):0;
      }

    httpx->state = HTTPX_SENDING_POSTDATA;
    if ( error )
      {
        Httpx_Do_Callback(httpx,HTTPX_BROKEN);

        return;
      }

    
    bf->count = 0;
    i = !httpx->left ? 0 : Oj_Read(httpx->poststrm,bf->at,Yo_MIN(httpx->left,bf->capacity),-1);
    httpx->left -= i;
    Httpx_Aio_Send(httpx, bf->at, i,
                          httpx->left ? Cbk_Httpx_Post : Cbk_Httpx_Requested);


  }
#endif
  ;
    
void Cbk_Httpx_Connected(YOYO_HTTPX *httpx, int error)
#ifdef _HTTPX_BUILTIN
  {
    httpx->state = HTTPX_CONNECTED;

    if ( error )

      {



        Httpx_Do_Callback(httpx,HTTPX_BROKEN

                               |((error&TCP_PERMANENT_ERROR)?HTTPX_PERMANENT_ERROR:0));
        return;
      }
      
    Httpx_Do_Callback(httpx,HTTPX_CONNECTED);
    
    /* httpx->bf contains prepared request */
    Httpx_Aio_Send(httpx, httpx->bf->at, httpx->bf->count,
                           (httpx->method == HTTPX_POST || httpx->method == HTTPX_PUT ) 
                                ?Cbk_Httpx_Post
                                :Cbk_Httpx_Requested);    
  }
#endif
  ;
  
void Cbk_Httpx_Proxy_Connected(YOYO_HTTPX *httpx, int error)
#ifdef _HTTPX_BUILTIN
  {
    httpx->state = HTTPX_PROXY_CONNECTED;

    if ( error )

      {



        Httpx_Do_Callback(httpx,HTTPX_BROKEN

                               |((error&TCP_PERMANENT_ERROR)?HTTPX_PERMANENT_ERROR:0));
        return;
      }
      
    Httpx_Do_Callback(httpx,HTTPX_PROXY_CONNECTED);
    
    /// auth / ssl connect
    Cbk_Httpx_Connected(httpx,error);
  }
#endif
  ;
  
void Httpx_Connect(YOYO_HTTPX *httpx)
#ifdef _HTTPX_BUILTIN
  {
    if ( httpx->keepalive && httpx->netchnl )
      {
        Httpx_Aio_Send(httpx, httpx->bf->at, httpx->bf->count,
                     (httpx->method == HTTPX_POST || httpx->method == HTTPX_PUT) 
                          ?Cbk_Httpx_Post
                          :Cbk_Httpx_Requested);    
      }
    else
      { 
        __Unrefe(httpx->netchnl);
        httpx->netchnl = __Refe(Tcp_Socket());
        
        if ( httpx->proxy_url )
          Tcp_Aio_Connect(httpx->netchnl,httpx->proxy_url->host,httpx->proxy_url->port
                                ,Cbk_Httpx_Proxy_Connected,httpx);
          
        else
          Tcp_Aio_Connect(httpx->netchnl,httpx->url->host,httpx->url->port
                              ,Cbk_Httpx_Connected,httpx);
      }
  }
#endif
  ;
  
void Httpx_Query(YOYO_HTTPX *httpx, int method, char *uri, YOYO_DICTO *hdrs, void *poststrm, void *contstrm, int maxcount)
#ifdef _HTTPX_BUILTIN
  {
    if ( httpx->status_text ) { free(httpx->status_text); httpx->status_text = 0; }
    httpx->interrupted = 0;
    httpx->status = 0;
    httpx->method = method;
    httpx->maxcount = maxcount?maxcount:INT_MAX;
................................................................................
    
    if ( !uri ) 
      uri = httpx->url->uri;
    else if ( uri[0] != '/' )
      uri = Str_Join_2('/',httpx->url->uri,uri);
    
    Build_Http_Request(httpx,method,uri,hdrs);
    Httpx_Connect(httpx);



  }
#endif
  ;
  
#define Httpx_Client(Url,Flags) Httpx_Client_Callback(Url,Flags,0,0)
YOYO_HTTPX *Httpx_Client_Callback(char *url,int flags, httpx_collback_t callback, void *cbkobj)
#ifdef _HTTPX_BUILTIN
................................................................................
      }

    return httpx;
  }
#endif
  ;

int Httpx_Perform_Query(YOYO_HTTPX *httpx)
#ifdef _HTTPX_BUILTIN
  {
    if ( httpx->async ) return 0;
    while ( httpx->state != HTTPX_FINISHED && !(httpx->state&HTTPX_BROKEN) )
      {
        Tasque_Perform_Update(10,0);
      }
    return httpx->status;
  }
#endif
  ;
  
int Httpx_Head(YOYO_HTTPX *httpx, char *uri)
#ifdef _HTTPX_BUILTIN
  {
    int ret;
    __Auto_Release
      {
        if ( !httpx ) 
          {
            httpx = Httpx_Client(uri,0);
            uri = 0;
          }
        Httpx_Query(httpx,HTTPX_GET,uri,0,0,0,0);
        ret = Httpx_Perform_Query(httpx);
      }
    return ret;
  }
#endif
  ;
  
int Httpx_Get(YOYO_HTTPX *httpx, char *uri, YOYO_DICTO *params, void *contstrm, int maxcount)
................................................................................
            uri = 0;
          }
        else
          {
            if ( uri && params )
              uri = Url_Compose(uri,params);
          }
        Httpx_Query(httpx,HTTPX_GET,uri,0,0,contstrm,maxcount);
        ret = Httpx_Perform_Query(httpx);
      }
    return ret;
  }
#endif
  ;
  
int Httpx_Post(YOYO_HTTPX *httpx, char *uri, YOYO_DICTO *params, void *contstrm, int maxcount)
................................................................................
          }
        if ( params ) 
          {
            char *encoded = Url_Xform_Encode(params);
            if ( encoded )
              poststrm = Memory_As_File(encoded,strlen(encoded));
          }
        Httpx_Query(httpx,HTTPX_POST,uri,0,poststrm,contstrm,maxcount);
        ret = Httpx_Perform_Query(httpx);
      }
    return ret;
  }
#endif
  ;
  
int Httpx_Content_Length(YOYO_HTTPX *httpx)

Changes to string.hc.

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  {
    STRICT_REQUIRE(E >= S);
    return Str_Copy_Npl(S,E-S);
  }
#endif
  ;

#define Str_Trim_Copy(Str,Len) Str_Trim_Copy_L(Str,-1)
#define Str_Trim_Copy_L(Str,Len) __Pool(Str_Trim_Copy_Npl(Str,Len))
char *Str_Trim_Copy_Npl(char *S, int L)
#ifdef _YOYO_STRING_BUILTIN
  {
    if ( L < 0 ) L = S?strlen(S):0;
    if ( L && S )
      {







|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  {
    STRICT_REQUIRE(E >= S);
    return Str_Copy_Npl(S,E-S);
  }
#endif
  ;

#define Str_Trim_Copy(Str) Str_Trim_Copy_L(Str,-1)
#define Str_Trim_Copy_L(Str,Len) __Pool(Str_Trim_Copy_Npl(Str,Len))
char *Str_Trim_Copy_Npl(char *S, int L)
#ifdef _YOYO_STRING_BUILTIN
  {
    if ( L < 0 ) L = S?strlen(S):0;
    if ( L && S )
      {

Changes to tcpip.hc.

45
46
47
48
49
50
51

52




















53
54
55
56
57





58

59
60
61

62






















































63
64
65
66
67
68
69
70








71


72
73
74
75
76
77
78
..
82
83
84
85
86
87
88

89

90
91
92
93
94
95
96
97
98
99
100

101
102
103

104



















105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128






129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159



160
161
162
163
164
165
166
...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
213
214
215
216
217
218
219


220


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256


257


258
259
260
261
262
263
264
265
266
267
268
269




























270


271
272
273






















































274




275
276
277
278












279

















280








































281
282
283
284
285
286
287
288
289
290
291
292
...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309










310
311
312






313
314
315
316
317

318
319
320
321
322


323
324
325
326
327
328


329
330
331
332
333
334
335

336
337
338
339
340
341
342
343
344














345
346
347
348
349
350

351
352
353
354
355
356

357
358
359
360
361
362
363
364
365
366

367
368
369
370
371
372
373
374
375
376
377
378
379
380

381
382
383
384
385

386
387
388
389
390
391
392
393















394
395
396
397
398
399
400
401
402
403
404

405
406
407
408

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

461
462
463

464



465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
...
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509


510
511
512
513
514
515
516
517

518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551


552




553
554

555
556
557




558
559
560
561
562
563
564
565



566

567
568

569
570
571
572






573
574
575
576
577
578
579
580
581
582

583
584
585
586
587
588
589
590







591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606

#ifndef C_once_F8F16072_F92E_49E7_A983_54F60965F4C9
#define C_once_F8F16072_F92E_49E7_A983_54F60965F4C9

#include "yoyo.hc"
#include "string.hc"
#include "file.hc"

#include "asio.hc"





















#ifdef _LIBYOYO
#define _YOYO_TCPIP_BUILTIN
#endif






enum  

  {
    TCPSOK_ASYNC = 1,
  };
























































typedef struct _YOYO_TCPSOK
  {
    ipaddr_t  ip;
    int       skt;
    int       port;
    int       async: 1;
  } YOYO_TCPSOK;









#ifdef __windoze



void _WSA_Term(void)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    WSACleanup();
  }
#endif
................................................................................
#ifdef _YOYO_TCPIP_BUILTIN
  {
    static int wsa_status = -1;
    static WSADATA wsa_data = {0};
    if ( wsa_status != 0 )
      {
        if ( 0 != WSAStartup(MAKEWORD(2, 2), &wsa_data) )

          __Raise(YOYO_ERROR_SUBSYSTEM_INIT,"failed to initialize WSA subsystem");

        else
          {
            wsa_status = 0;
            atexit(_WSA_Term);
          }
      }
  }
#endif
  ;

#else

#define _WSA_Init()
#endif






















#define Ipv4_Format(Ip) __Pool(Ipv4_Format_Npl(Ip))
char *Ipv4_Format_Npl(ipaddr_t _ip)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    uint_t ip = (uint_t)_ip;
    return __Format_Npl("%d.%d.%d.%d"
              ,(ip&0x0ff)
              ,((ip>>8)&0x0ff)
              ,((ip>>16)&0x0ff)
              ,((ip>>24)&0x0ff));
  }
#endif
  ;
  
/***
!!
!!  Can be used in Threaded worker!
!!
***/
int Dns_IPv4_Resolve(char *host, ipaddr_t *ip)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    struct hostent *hstn = 0;
    *ip = 0;






        
    if ( !strcmp_I(host,"localhost") ) 
      {
        *ip = 0x0100007f;
        return 0;
      }
      
    *ip = inet_addr(host);
    if ( *ip != 0x0ffffffff ) return 0;
  l:
    if ( hstn = gethostbyname(host) )
      {
        memcpy(ip,hstn->h_addr,Yo_MAX(sizeof(*ip),hstn->h_length));
        return 0;
      }
    else
      {
        int err = h_errno;
        if ( err == TRY_AGAIN )
          goto l;
        return err;
      }
    return 0;
  }        
#endif
  ;

ipaddr_t Dns_Resolve(char *host)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    ipaddr_t ip;



    switch ( Dns_IPv4_Resolve(host,&ip) )
      {
        case 0:
          break;
        case NO_RECOVERY:
          __Raise(YOYO_ERROR_DNS,"unrecoverable DNS error");
        default: 
................................................................................
  ;
  
void Tcp_Graceful_Close(YOYO_TCPSOK *sok)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( sok->skt != INVALID_SOCKET ) 
      {
        shutdown(sok->skt,SB_BOTH);
        Tcp_Close(sok);
      }
  }
#endif
  ;

void YOYO_TCPSOK_Destruct(YOYO_TCPSOK *sok)
................................................................................
  {
    byte_t *b = out;
    int cc = count;
    while ( cc )
      {
        int q = recv(sok->skt,b,cc,0);
        if ( q < 0 )


          __Raise_Format(YOYO_ERROR_IO,("tcp recv failed with error %s",strerror(errno)));


        STRICT_REQUIRE( q <= cc );
        cc -= q;
        b += q;
        if ( count-cc >= mincount )
          break;
      }
    return count-cc;
  }
#endif
  ;

int Tcp_Asio_Recv(YOYO_TCPSOK *sok,void *out, int count, int mincount, void *obj, asio_recv_callback_t callback)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( sok->async )
      return Asio_Recv(sok->skt,out,count,mincount,obj,callback);
    else
      {
        int cc = Tcp_Read(sok,out,count,mincount);
        if ( callback )
          return callback(obj,ASIO_COMPLETED|ASIO_SYNCHRONOUS,cc);
      }
    return 0;
  }
#endif
  ;

int Tcp_Write(YOYO_TCPSOK *sok, void *out, int count, int mincount)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    byte_t *b = out;
    int cc = count;
    while ( cc )
      {
        int q = send(sok->skt,b,cc,0);
        if ( q < 0 )


          __Raise_Format(YOYO_ERROR_IO,("tcp send failed with error %s",strerror(errno)));


        STRICT_REQUIRE( q <= cc );
        cc -= q;
        b += q;
        if ( q == 0 && count-cc >= mincount )
          break;
      }
    return count-cc;
  }
#endif
  ;
  
int Tcp_Asio_Send(YOYO_TCPSOK *sok,void *out, int count, void *obj, asio_send_callback_t callback)




























#ifdef _YOYO_TCPIP_BUILTIN


  {
    if ( sok->async )
      return Asio_Send(sok->skt,out,count,obj,callback);






















































    else




      {
        int cc = Tcp_Write(sok,out,count,count);
        if ( callback )
          return callback(obj,ASIO_COMPLETED|ASIO_SYNCHRONOUS);












      }

















    return 0;








































  }
#endif
  ;
  
YOYO_TCPSOK *Tcp_Socket(int flags)
#ifdef _YOYO_TCPIP_BUILTIN  
  {
    static YOYO_FUNCTABLE funcs[] = 
      { {0},
        {Oj_Destruct_OjMID,    YOYO_TCPSOK_Destruct},
        {Oj_Close_OjMID,       Tcp_Close},
        {Oj_Read_OjMID,        Tcp_Read},
................................................................................
        //{Oj_Available_OjMID,   Tcp_Available},
        //{Oj_Eof_OjMID,         Tcp_Eof},
        {0}
      };

    YOYO_TCPSOK *sok = __Object(sizeof(YOYO_TCPSOK),funcs);
    sok->skt = INVALID_SOCKET;
    if ( flags & TCPSOK_ASYNC ) sok->async = 1;
    return sok;
  }
#endif
  ;
  
void Tcp_Set_Async(socket_t skt)
#ifdef _YOYO_TCPIP_BUILTIN  
  {










  #ifdef __windoze
    ulong_t nonblock = 1;
    ioctlsocket(skt, FIONBIO, &nonblock);






  #else       
    int arg = fcntl(skt,F_GETFL,0);
    arg |= O_NONBLOCK; 
    fcntl(skt,F_SETFL,arg); 
  #endif

  }
#endif
  ;
    
#define Tcp_IPv4_Connect(Sok,Ip,Port) Tcp_Asio_IPv4_Connet(Sok,Ip,Port,0,0)


int Tcp_Asio_IPv4_Connect(YOYO_TCPSOK *sok, ipaddr_t ip, int port, void *obj, asio_notify_callback_t callback)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    struct sockaddr_in addr = {0}; 
    socket_t skt;
    int conerr;


    
    _WSA_Init();
    
    addr.sin_family = AF_INET;
    addr.sin_port   = htons(port);
    addr.sin_addr.s_addr = (ulong_t)ip;
    

    sok->port = port;
    sok->ip = ip;
    
    skt = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    sok->skt = skt;

    if ( skt != INVALID_SOCKET && sok->async )
      Tcp_Set_Async(skt);
          














    conerr = (skt != INVALID_SOCKET ) ? connect(skt,(struct sockaddr*)&addr,sizeof(addr)) : -1;
    
    if ( conerr < 0 )
      {
        if ( skt == INVALID_SOCKET || !sok->async )
          {

            __Raise_Format(YOYO_ERROR_IO,
                            (__yoTa("tcp connection failed: sok %d, point %s:%d, error %d",0)
                            ,skt
                            ,Ipv4_Format(ip)
                            ,port
                            ,conerr));

          }
        else if ( sok->async && Asio_Status_Repeat_Or_Die() == ASIO_PENGING && callback )
          {
            return Asio_Notify(skt,obj,callback);
          }
      }
      
    if ( callback ) 
      return callback(obj,ASIO_COMPLETED|(sok->async?ASIO_SYNCHRONOUS:0));
    return 0;

  }
#endif
  ;

typedef struct _YOYO_HOST_RESOLVE
  {
    char *host;
    void *cbkobj;
    asio_resolve_callback_t callback;
    int err;
    ipaddr_t ip; 
  } YOYO_HOST_RESOLVE;

void YOYO_HOST_RESOLVE_Destruct(YOYO_HOST_RESOLVE *o)

#ifdef _YOYO_TCPIP_BUILTIN
  {
    free(o->host);
    __Unrefe(o->cbkobj);
    __Destruct(o);

  }
#endif
  ;
  
void Wrk_Tcp_Asio_IPv4_Resolve(YOYO_HOST_RESOLVE *o)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    o->err = Dns_IPv4_Resolve(o->host,&o->ip);















  }
#endif
  ;
  
int Cbk_Tcp_Asio_IPv4_Resolve(YOYO_HOST_RESOLVE *o, int status)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( o->callback ) 
      {
        if ( o->err )
          if ( o->err == HOST_NOT_FOUND )

            return o->callback(o->cbkobj,ASIO_FAILED|ASIO_PERMANANT_ERROR,o->ip);
          else
            return o->callback(o->cbkobj,ASIO_FAILED,o->ip);
        return o->callback(o->cbkobj,0,o->ip);

      }
    return 0;
  }
#endif
  ;
    
int Tcp_Asio_IPv4_Resolve(char *host, asio_resolve_callback_t callback, void *obj)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    YOYO_HOST_RESOLVE *o = __Object_Dtor(sizeof(YOYO_HOST_RESOLVE),YOYO_HOST_RESOLVE_Destruct);
    o->host = Str_Copy_Npl(host,-1);
    o->callback = callback;
    o->cbkobj = __Refe(obj);
    Asio_Thr_Worker(Wrk_Tcp_Asio_IPv4_Resolve,Cbk_Tcp_Asio_IPv4_Resolve,o);
    return 0;
  }
#endif
  ;
  
typedef struct _YOYO_HOST_CONNECT
  {
    YOYO_TCPSOK *sok;
    int port;
    void *cbkobj;
    asio_notify_callback_t callback;
  } YOYO_HOST_CONNECT;
  
void YOYO_HOST_CONNECT_Destruct(YOYO_HOST_CONNECT *o)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    __Unrefe(o->sok);
    __Unrefe(o->cbkobj);
    __Destruct(o);
  }
#endif
  ;
    
int Cbk_Tcp_Asio_Host_Connect(YOYO_HOST_CONNECT *o,int status,ipaddr_t ip)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( !ASIO_ST_SUCCEEDED(status) || status == ASIO_TIMER )
      return ( o->callback ) ? o->callback( o->cbkobj, status ) : 0;
    else
      return Tcp_Asio_IPv4_Connect(o->sok,ip,o->port,o->cbkobj,o->callback);
  }
#endif
  ;
      
#define Tcp_Connect(Sok,Host,Port) Tcp_Asio_Connect(Sok,Host,Port,0,0)
int Tcp_Asio_Connect(YOYO_TCPSOK *sok,char *host,int port,void *obj,asio_notify_callback_t callback)
#ifdef _YOYO_TCPIP_BUILTIN
  {

    _WSA_Init();
    
    if ( sok->async )

      {



        YOYO_HOST_CONNECT *o = __Object_Dtor(sizeof(YOYO_HOST_CONNECT),YOYO_HOST_CONNECT_Destruct);
        o->sok = __Refe(sok);
        o->port = port;
        o->cbkobj = __Refe(obj);
        o->callback = callback;
        return Tcp_Asio_IPv4_Resolve(host,Cbk_Tcp_Asio_Host_Connect,o);
      }
    else
      {
        ipaddr_t ip = 0;
        __Try_Except
          ip = Dns_Resolve(host);
        __Except
          if ( callback ) 
            return callback(obj,ASIO_FAILED|ASIO_SYNCHRONOUS);
        return Tcp_Asio_IPv4_Connect(sok,ip,port,obj,callback);    
      }
  }
#endif
  ;

YOYO_TCPSOK *Tcp_Open(char *host, int port)
#ifdef _YOYO_TCPIP_BUILTIN
  {
................................................................................
    YOYO_TCPSOK *sok = Tcp_Socket(0);
    Tcp_Connect(sok,host,port);
    return sok;
  }
#endif
  ;

void Tcp_Asio_Interrupt(YOYO_TCPSOK *sok)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    Asio_Interrupt(sok->skt);
  }
#endif
  ;

YOYO_TCPSOK *Tcp_Listen(int flags, char *host,int port,int listlen)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    YOYO_TCPSOK *sok;
    struct sockaddr_in addr = {0}; 
    ipaddr_t ip;


    
    _WSA_Init();
    
    ip = host?Dns_Resolve(host):0;

    addr.sin_family = AF_INET;
    addr.sin_port   = htons(port);
    addr.sin_addr.s_addr = (ulong_t)ip;

    
    sok = __Refe(Tcp_Socket(0));
    sok->port = port;
    sok->ip = ip;
    
    if ( INVALID_SOCKET == (sok->skt = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) )  goto sok_error;
    if ( -1 == bind(sok->skt,(struct sockaddr*)&addr,sizeof(addr)) ) goto sok_error;
    if ( -1 == listen(sok->skt,(listlen?listlen:SOMAXCONN)) ) goto sok_error;

    if ( sok->skt == INVALID_SOCKET )
      {       
    sok_error: 
        __Raise_Format(YOYO_ERROR_IO,
                        (__yoTa("tcp bind/listen failed: sok %d, point %s:%d, error %s",0)
                        ,sok->skt
                        ,Ipv4_Format(ip)
                        ,port
                        ,Format_Network_Error()));
      }
    else if ( flags & TCPSOK_ASYNC )
      Tcp_Set_Async(sok->skt);
      
    return sok;
  }
#endif
  ;

typedef int (*tcp_accept_callback_t)(void *obj,int status,YOYO_TCPSOK *sok);

#ifdef _YOYO_TCPIP_BUILTIN
typedef struct _YOYO_TCPSOK_ACCEPT
  {
    void *obj;
    tcp_accept_callback_t callback;


  } YOYO_TCPSOK_ACCEPT;





void YOYO_TCPSOK_ACCEPT_Destruct(YOYO_TCPSOK_ACCEPT *acbk)

  {
    __Unrefe(acbk->obj);
    __Destruct(acbk);




  }

YOYO_TCPSOK_ACCEPT *Tcp_Accept_Callback(void *obj,tcp_accept_callback_t callback)
  {
    YOYO_TCPSOK_ACCEPT *acbk = __Object_Dtor(sizeof(YOYO_TCPSOK_ACCEPT),YOYO_TCPSOK_ACCEPT_Destruct);
    acbk->callback = callback;
    acbk->obj = __Refe(obj);
    return acbk;



  }


int Cbk_Tcp_Asio_Accept(void *obj, int status, int _, longptr_t _skt, struct sockaddr *_addr)

  {
    socket_t skt = (socket_t)_skt;
    if ( status == ASIO_TIMER || !ASIO_ST_SUCCEEDED(status) )
      return ((YOYO_TCPSOK_ACCEPT*)obj)->callback(((YOYO_TCPSOK_ACCEPT*)obj)->obj,status,0);






    else
      {
        struct sockaddr_in *addr = ((struct sockaddr_in*)_addr);
        YOYO_TCPSOK *sok = Tcp_Socket( (status&ASIO_SYNCHRONOUS)?0:TCPSOK_ASYNC );
        sok->ip = addr->sin_addr.s_addr;
        sok->port = ntohs(addr->sin_port);
        sok->skt = skt;
        if ( sok->async )
          Tcp_Set_Async(sok->skt);
        return ((YOYO_TCPSOK_ACCEPT*)obj)->callback(((YOYO_TCPSOK_ACCEPT*)obj)->obj,status,sok);

      }
  }
#endif

int Tcp_Asio_Accept(YOYO_TCPSOK *sok, void *obj, tcp_accept_callback_t callback)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    return Asio_Accept(sok->skt,Tcp_Accept_Callback(obj,callback),Cbk_Tcp_Asio_Accept);







  }
#endif
  ;

void Tcp_Asio_Shutdown(YOYO_TCPSOK *sok)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( sok->skt != INVALID_SOCKET )
      Asio_Interrupt(sok->skt);
    Tcp_Graceful_Close(sok);
  }
#endif
  ;

#endif /* C_once_F8F16072_F92E_49E7_A983_54F60965F4C9 */








>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





>
>
>
>
>
|
>
|
<
<
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





<


>
>
>
>
>
>
>
>

>
>







 







>
|
>











>
|


>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|


<

|
|
|
|




<
<
<
<
<




<
>
>
>
>
>
>



|



|
|



|




|













>
>
>







 







|







 







>
>
|
>
>








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












>
>
|
>
>










|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
|
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
|
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|







 







<




|
|
|

>
>
>
>
>
>
>
>
>
>
|
<
<
>
>
>
>
>
>
|
<
<
<
<
>



|
|
>
>
|


<


>
>


|
<
<
<
<
>

|




|
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
<
<
>

|

|

<
>

<
|
<
<
<
<
<
<
|
>




<
|
<
<
<
<
<
<
<
<
>


<
<
<
>




|


|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|
|


|
|
|
<
>
|
|
|
|
>

<



|
<
<
<
<
<
<
<
<
<
<
<
<
<





|












|


|
|

|




<
|


>
|
|
|
>
|
>
>
>
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
|



<

>
>

<
<
|
<
<
<
<
>






|








|

|

<
<






|

|
<

<
<
>
>
|
>
>
>
>
|
<
>
|
<
<
>
>
>
>
|
|
<
|
<
<
<
<
>
>
>
|
>
|
<
>
|
<
<
<
>
>
>
>
>
>


<
<
<
<
|
<
<
<
>




|


|
>
>
>
>
>
>
>




<
<
<
<
<
|
<
<
<



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86


87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
228
229





230
231
232
233

234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
















347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406


407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466



467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
...
551
552
553
554
555
556
557

558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576


577
578
579
580
581
582
583




584
585
586
587
588
589
590
591
592
593
594

595
596
597
598
599
600
601




602
603
604
605
606
607
608
609

610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628


629
630
631
632
633
634

635
636

637






638
639
640
641
642
643

644








645
646
647



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681

682
683
684
685
686
687
688

689
690
691
692













693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721

722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739











740
741
742
743
744
745
746
...
747
748
749
750
751
752
753








754
755
756
757

758
759
760
761


762




763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782


783
784
785
786
787
788
789
790
791

792


793
794
795
796
797
798
799
800

801
802


803
804
805
806
807
808

809




810
811
812
813
814
815

816
817



818
819
820
821
822
823
824
825




826



827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846





847



848
849
850

#ifndef C_once_F8F16072_F92E_49E7_A983_54F60965F4C9
#define C_once_F8F16072_F92E_49E7_A983_54F60965F4C9

#include "yoyo.hc"
#include "string.hc"
#include "file.hc"
#include "datetime.hc"
#include "tasque.hc"

#ifdef _MSC_VER
#pragma comment(lib,"ws2_32.lib")
#endif

#ifdef __windoze
  #include <winsock2.h>
  #ifdef _IPV6
    #include <ws2tcpip.h>
  #endif
  typedef SOCKET socket_t;
#else
  #include <errno.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <netdb.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  typedef int socket_t;
#endif

#ifdef _LIBYOYO
#define _YOYO_TCPIP_BUILTIN
#endif

typedef struct ipaddr_t 
  { 
    u32_t v4;
  #ifdef _IPV6
    u16_t e6[6];
  #endif 
  } ipaddr_t;



typedef struct 
  {
    struct sockaddr_in addr4;
  #ifdef _IPV6
    struct sockaddr_in6 addr6;
  #endif
  } IPV4V6_ADDR_MIX;

void Tcp_Expand_Ip_Addr(ipaddr_t *ip, int port, IPV4V6_ADDR_MIX *addr, int *addr_len)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    memset(addr,0,sizeof(*addr));
    #ifdef _IPV6
    if ( !memcmp( ip->e6, "\xff\xff\0\0\0\0\0\0\0\0\0\0", 12) )
      {
    #endif
        addr->addr4.sin_family = AF_INET;
        addr->addr4.sin_port   = htons(port);
        addr->addr4.sin_addr.s_addr = ip->v4;
        *addr_len = sizeof(addr->addr4);
    #ifdef _IPV6
      }
    else
      {
        addr->addr6.sin6_family = AF_INET6;
        addr->addr6.sin6_port   = htons(port);
        memcpy(&addr->addr6.sin6_addr,ip,sizeof(*ip));
        *addr_len = sizeof(addr->addr6);
      }
    #endif
  } 
#endif
  ;
  
ipaddr_t Tcp_Sin_Ip(void *_a)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    ipaddr_t ip;
    struct sockaddr_in *a = _a;
    memset(&ip,sizeof(ip),0);
    if ( a->sin_family == AF_INET ) 
      {
        ip.v4 = (ulong_t)a->sin_addr.s_addr;
  #ifdef _IPV6
        ip.e6[0] = 0x0ffff;
      }
    else if ( ((struct sockaddr_in6*)a)->sin6_family == AF_INET6 )
      {
        memcpy(&ip,&((struct sockaddr_in6*)a)->sin6_addr,sizeof(ip));
  #endif  
      }
    return ip; 
  }
#endif
  ;
  
typedef struct _YOYO_TCPSOK
  {
    ipaddr_t  ip;
    int       skt;
    int       port;

  } YOYO_TCPSOK;

enum  
  {
    TCP_AIO_COMPLETE    = 0,
    TCP_AIO_FAIL        = 0x80000000,
    TCP_PERMANENT_ERROR = 0x40000000,
    TCP_IS_CLOSED       = 0x20000000,
  };

#ifdef __windoze

#define Tcp_Errno() WSAGetLastError()

void _WSA_Term(void)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    WSACleanup();
  }
#endif
................................................................................
#ifdef _YOYO_TCPIP_BUILTIN
  {
    static int wsa_status = -1;
    static WSADATA wsa_data = {0};
    if ( wsa_status != 0 )
      {
        if ( 0 != WSAStartup(MAKEWORD(2, 2), &wsa_data) )
          { 
            __Raise(YOYO_ERROR_SUBSYSTEM_INIT,"failed to initialize WSA subsystem");
          }
        else
          {
            wsa_status = 0;
            atexit(_WSA_Term);
          }
      }
  }
#endif
  ;

#else
#define Tcp_Errno() errno
#define _WSA_Init() 
#endif

#define Tcp_Format_Error() Tcp_Format_Error_Code(Tcp_Errno())

char *Tcp_Format_Error_Code(int err)
#ifdef _YOYO_TCPIP_BUILTIN
  {
  #ifdef __windoze
    char *msg = __Malloc(1024);
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
                  FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, err,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPSTR)msg, 1024,0);
    return msg;  
  #else
    return strerror(errno);
  #endif
  }
#endif
  ;

#define Ip_Format(Ip) Ipv4_Format(Ip)
#define Ip_Format_Npl(Ip) Ipv4_Format_Npl(Ip)
#define Ipv4_Format(Ip) __Pool(Ipv4_Format_Npl(Ip))
char *Ipv4_Format_Npl(ipaddr_t ip)
#ifdef _YOYO_TCPIP_BUILTIN
  {

    return __Format_Npl("%d.%d.%d.%d"
              ,( ip.v4     &0x0ff)
              ,((ip.v4>>8) &0x0ff)
              ,((ip.v4>>16)&0x0ff)
              ,((ip.v4>>24)&0x0ff));
  }
#endif
  ;
  





int Dns_IPv4_Resolve(char *host, ipaddr_t *ip)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    struct hostent *hstn = 0;

   
    memset(ip,0,sizeof(*ip));
  
  #ifdef _IPV6
    ip->e6[0] = 0x0ffff;
  #endif
        
    if ( !strcmp_I(host,"localhost") ) 
      {
        ip->v4 = 0x0100007f;
        return 0;
      }
      
    ip->v4 = inet_addr(host);
    if ( ip->v4 != 0x0ffffffff ) return 0;
  l:
    if ( hstn = gethostbyname(host) )
      {
        memcpy(&ip->v4,hstn->h_addr,Yo_MAX(sizeof(ip->v4),hstn->h_length));
        return 0;
      }
    else
      {
        int err = Tcp_Errno();
        if ( err == TRY_AGAIN )
          goto l;
        return err;
      }
    return 0;
  }        
#endif
  ;

ipaddr_t Dns_Resolve(char *host)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    ipaddr_t ip;

    _WSA_Init();

    switch ( Dns_IPv4_Resolve(host,&ip) )
      {
        case 0:
          break;
        case NO_RECOVERY:
          __Raise(YOYO_ERROR_DNS,"unrecoverable DNS error");
        default: 
................................................................................
  ;
  
void Tcp_Graceful_Close(YOYO_TCPSOK *sok)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( sok->skt != INVALID_SOCKET ) 
      {
        shutdown(sok->skt,SD_SEND);
        Tcp_Close(sok);
      }
  }
#endif
  ;

void YOYO_TCPSOK_Destruct(YOYO_TCPSOK *sok)
................................................................................
  {
    byte_t *b = out;
    int cc = count;
    while ( cc )
      {
        int q = recv(sok->skt,b,cc,0);
        if ( q < 0 )
          {
            int err = Tcp_Errno();
            __Raise_Format(YOYO_ERROR_IO,(__yoTa("tcp recv failed with error %s",0),
                                          Tcp_Format_Error_Code(err)));
          }
        STRICT_REQUIRE( q <= cc );
        cc -= q;
        b += q;
        if ( count-cc >= mincount )
          break;
      }
    return count-cc;
  }
















#endif
  ;

int Tcp_Write(YOYO_TCPSOK *sok, void *out, int count, int mincount)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    byte_t *b = out;
    int cc = count;
    while ( cc )
      {
        int q = send(sok->skt,b,cc,0);
        if ( q < 0 )
          {
            int err = Tcp_Errno();
            __Raise_Format(YOYO_ERROR_IO,(__yoTa("tcp send failed with error %s",0),
                                          Tcp_Format_Error_Code(err)));
          }
        STRICT_REQUIRE( q <= cc );
        cc -= q;
        b += q;
        if ( q == 0 && count-cc >= mincount )
          break;
      }
    return count-cc;
  }
#endif
  ;
 

typedef void (*tcp_resolve_callback_t)(void *obj, int status, ipaddr_t ip);
typedef void (*tcp_recv_callback_t)(void *obj, int status, int count);
typedef void (*tcp_send_callback_t)(void *obj, int status);
typedef void (*tcp_accept_callback_t)(void *obj, int status, YOYO_TCPSOK *sok);
typedef void (*tcp_any_callback_t)(void *obj, int status, ...);
typedef void (*tcp_connect_callback_t)(void *obj,int status);

typedef struct _YOYO_TCP_IOT
  {
    socket_t skt;
    union 
      {
        uquad_t accum;
        ipaddr_t ip; 
        IPV4V6_ADDR_MIX addr;
      };
    union
      {
        int mincount;
        int port;
      };
    int err, count;
    void *obj, *dta;
    char *host;
    tcp_any_callback_t cbk;
    struct _YOYO_TCP_IOT *next;
  } YOYO_TCP_IOT;
 
#ifdef _YOYO_TCPIP_BUILTIN
static YOYO_TCP_IOT *Tcp_Iot_Pool = 0;
#endif



void YOYO_TCP_IOT_Destruct(YOYO_TCP_IOT *iot)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    free(iot->host);
    __Unrefe(iot->obj);
    iot->next = Tcp_Iot_Pool;
    Tcp_Iot_Pool = iot;
    __Destruct(iot);
  }
#endif
  ;

YOYO_TCP_IOT *Tcp_Alloc_Iot()
#ifdef _YOYO_TCPIP_BUILTIN
  {
    return __Object_Dtor(sizeof(YOYO_TCP_IOT),YOYO_TCP_IOT_Destruct);
  }
#endif
  ;
  
void Wrk_Tcp_Send(YOYO_TCP_IOT *iot)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    byte_t *b = iot->dta;
    int count = iot->count;
    int cc = count;
    while ( cc )
      {
        int q = send(iot->skt,b,cc,0);
        if ( q < 0 )
          {
            iot->count = count-cc;
            iot->err = Tcp_Errno();
            return;
          }
        STRICT_REQUIRE( q <= cc );
        cc -= q;
        b += q;
        if ( count-cc >= iot->mincount )
          break;
      }
    iot->count = count-cc;
    iot->err = 0;
  }
#endif
  ;
  
void Cbk_Tcp_Send(YOYO_TCPSOK *sok, YOYO_TCP_IOT *iot, int status)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( iot->err && sok->skt == INVALID_SOCKET )
      iot->cbk(iot->obj,TCP_AIO_FAIL|TCP_PERMANENT_ERROR|TCP_IS_CLOSED);
    else if ( status || iot->err )
      iot->cbk(iot->obj,TCP_AIO_FAIL);
    else
      iot->cbk(iot->obj,TCP_AIO_COMPLETE);
  }
#endif
  ;
    



void Tcp_Aio_Send(YOYO_TCPSOK *sok, void *out, int count, tcp_send_callback_t callback, void *obj)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    __Auto_Release 
      {
        YOYO_TCP_IOT *iot = Tcp_Alloc_Iot();
        iot->skt = sok->skt;
        iot->cbk = (tcp_any_callback_t)callback;
        iot->mincount = iot->count = count;
        iot->dta = out;
        iot->obj = __Refe(obj);
        Tasque_Queue(Wrk_Tcp_Send,iot,Cbk_Tcp_Send,sok);
      }
  }
#endif
  ;

void Wrk_Tcp_Recv(YOYO_TCP_IOT *iot)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    byte_t *b = iot->dta;
    int count = iot->count;
    int cc = count;
    while ( cc )
      {
        int q = recv(iot->skt,b,cc,0);
        if ( q < 0 )
          {
            iot->count = count-cc;
            iot->err = Tcp_Errno();
            return;
          }
        STRICT_REQUIRE( q <= cc );
        cc -= q;
        b += q;
        if ( count-cc >= iot->mincount )
          break;
      }
    iot->count = count-cc;
    iot->err = 0;
  }
#endif
  ;
  
void Cbk_Tcp_Recv(YOYO_TCPSOK *sok, YOYO_TCP_IOT *iot, int status)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( iot->err && sok->skt == INVALID_SOCKET )
      iot->cbk(iot->obj,TCP_AIO_FAIL|TCP_PERMANENT_ERROR|TCP_IS_CLOSED,0);
    else if ( status || iot->err )
      iot->cbk(iot->obj,TCP_AIO_FAIL,0);
    else
      iot->cbk(iot->obj,TCP_AIO_COMPLETE,iot->count);
  }
#endif
  ;
    
void Tcp_Aio_Recv(YOYO_TCPSOK *sok, void *out, int count, int mincount, tcp_recv_callback_t callback, void *obj)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    __Auto_Release 
      {
        YOYO_TCP_IOT *iot = Tcp_Alloc_Iot();
        iot->skt = sok->skt;
        iot->cbk = (tcp_any_callback_t)callback;
        iot->count = count;
        iot->mincount = mincount?mincount:count;
        iot->dta = out;
        iot->obj = __Refe(obj);
        Tasque_Queue(Wrk_Tcp_Recv,iot,Cbk_Tcp_Recv,sok);
      }
  }
#endif
  ;
  
YOYO_TCPSOK *Tcp_Socket()
#ifdef _YOYO_TCPIP_BUILTIN  
  {
    static YOYO_FUNCTABLE funcs[] = 
      { {0},
        {Oj_Destruct_OjMID,    YOYO_TCPSOK_Destruct},
        {Oj_Close_OjMID,       Tcp_Close},
        {Oj_Read_OjMID,        Tcp_Read},
................................................................................
        //{Oj_Available_OjMID,   Tcp_Available},
        //{Oj_Eof_OjMID,         Tcp_Eof},
        {0}
      };

    YOYO_TCPSOK *sok = __Object(sizeof(YOYO_TCPSOK),funcs);
    sok->skt = INVALID_SOCKET;

    return sok;
  }
#endif
  ;

void Wrk_Tcp_Connect(YOYO_TCP_IOT *iot)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( iot->skt != INVALID_SOCKET )
      { 
        if ( 0 > connect(iot->skt,(struct sockaddr *)&iot->addr,iot->count) )
          iot->err = Tcp_Errno();
      }
  }
#endif
  ;
  
void Cbk_Tcp_Connect(YOYO_TCPSOK *sok, YOYO_TCP_IOT *iot, int status)
#ifdef _YOYO_TCPIP_BUILTIN


  {
    if ( iot->err || status )
      {
        Tcp_Close(sok);
        iot->cbk(iot->obj,TCP_AIO_FAIL);
      }
    else




      iot->cbk(iot->obj,TCP_AIO_COMPLETE);
  }
#endif
  ;
        
#define Tcp_Ip_Connect(Sok,Ip,Port) Tcp_Ip_Connect_(0,Sok,Ip,Port,0,0)
#define Tcp_Aio_Ip_Connect(Sok,Ip,Port,callback,obj) Tcp_Ip_Connect_(1,Sok,Ip,Port,callback,obj)

int Tcp_Ip_Connect_(int use_aio, YOYO_TCPSOK *sok, ipaddr_t ip, int port, tcp_connect_callback_t callback, void *obj)
#ifdef _YOYO_TCPIP_BUILTIN
  {

    socket_t skt;
    int conerr;
    int addr_len = 0;
    IPV4V6_ADDR_MIX addr;
    
    _WSA_Init();





    Tcp_Expand_Ip_Addr(&ip,port,&addr,&addr_len);
    sok->port = port;
    sok->ip   = ip;
    
    skt = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    sok->skt = skt;

    if ( use_aio )

      {
        __Auto_Release
          {
            YOYO_TCP_IOT *iot = Tcp_Alloc_Iot();
            memcpy(&iot->addr,&addr,sizeof(addr));
            iot->count = addr_len;
            iot->skt = sok->skt;
            iot->cbk = callback;
            iot->obj = __Refe(obj);
            Tasque_Queue(Wrk_Tcp_Connect,iot,Cbk_Tcp_Connect,sok);
          }
        return 0;
      }
    else
      {
        conerr = (skt != INVALID_SOCKET ) ? connect(skt,(struct sockaddr*)&addr,addr_len) : -1;
        
        if ( conerr < 0 )
          {


            int err = Tcp_Errno();
            __Raise_Format(YOYO_ERROR_IO,
                            (__yoTa("tcp connection failed: sok %d, point %s:%d, error %s",0)
                            ,skt
                            ,Ip_Format(ip)
                            ,port

                            ,Tcp_Format_Error_Code(err)));
          }

          






        return 0;
      }
  }
#endif
  ;


  








void Wrk_Tcp_Resolve(YOYO_TCP_IOT *iot)
#ifdef _YOYO_TCPIP_BUILTIN
  {



    iot->err = Dns_IPv4_Resolve(iot->host,&iot->ip);
  }
#endif
  ;
  
void Cbk_Tcp_Resolve(void *_, YOYO_TCP_IOT *iot, int status)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( iot->cbk ) 
      {
        if ( status )
          {
            iot->cbk(iot->obj,TCP_AIO_FAIL,0);
          }
        else if ( iot->err )
          {
            if ( iot->err == HOST_NOT_FOUND )
              iot->cbk(iot->obj,TCP_AIO_FAIL|TCP_PERMANENT_ERROR,iot->ip);
            else
              iot->cbk(iot->obj,TCP_AIO_FAIL,iot->ip);
          }
        else
          iot->cbk(iot->obj,0,iot->ip);
      }
  }
#endif
  ;
   
void Tcp_Aio_Resolve(char *host, tcp_resolve_callback_t callback, void *obj)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    _WSA_Init();

    __Auto_Release

      { 
        YOYO_TCP_IOT *o = Tcp_Alloc_Iot();
        o->host = Str_Copy_Npl(host,-1);
        o->cbk = callback;
        o->obj = __Refe(obj);
        Tasque_Queue(Wrk_Tcp_Resolve,o,Cbk_Tcp_Resolve,0);
      }

  }
#endif
  ;














typedef struct _YOYO_HOST_CONNECT
  {
    YOYO_TCPSOK *sok;
    int port;
    void *cbkobj;
    tcp_connect_callback_t callback;
  } YOYO_HOST_CONNECT;
  
void YOYO_HOST_CONNECT_Destruct(YOYO_HOST_CONNECT *o)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    __Unrefe(o->sok);
    __Unrefe(o->cbkobj);
    __Destruct(o);
  }
#endif
  ;
    
void Cbk_Tcp_Host_Connect(YOYO_HOST_CONNECT *o, int status, ipaddr_t ip)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    if ( status )
      ( o->callback ) ? o->callback( o->cbkobj, status ) : 0;
    else
      Tcp_Aio_Ip_Connect(o->sok,ip,o->port,o->callback,o->cbkobj);
  }
#endif
  ;
      

void Tcp_Connect(YOYO_TCPSOK *sok,char *host,int port)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    ipaddr_t ip = Dns_Resolve(host);
    Tcp_Ip_Connect(sok,ip,port);    
  }
#endif
  ;

void Tcp_Aio_Connect(YOYO_TCPSOK *sok,char *host,int port,tcp_connect_callback_t callback,void *obj)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    YOYO_HOST_CONNECT *o = __Object_Dtor(sizeof(YOYO_HOST_CONNECT),YOYO_HOST_CONNECT_Destruct);
    o->sok = __Refe(sok);
    o->port = port;
    o->cbkobj = __Refe(obj);
    o->callback = callback;
    Tcp_Aio_Resolve(host,Cbk_Tcp_Host_Connect,o);











  }
#endif
  ;

YOYO_TCPSOK *Tcp_Open(char *host, int port)
#ifdef _YOYO_TCPIP_BUILTIN
  {
................................................................................
    YOYO_TCPSOK *sok = Tcp_Socket(0);
    Tcp_Connect(sok,host,port);
    return sok;
  }
#endif
  ;









YOYO_TCPSOK *Tcp_Listen(char *host, int port, int listlen)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    YOYO_TCPSOK *sok;

    ipaddr_t ip;
    int addr_len = 0;
    IPV4V6_ADDR_MIX addr;
    


    ip = Dns_Resolve(host);




    Tcp_Expand_Ip_Addr(&ip,port,&addr,&addr_len);
    
    sok = __Refe(Tcp_Socket(0));
    sok->port = port;
    sok->ip = ip;
    
    if ( INVALID_SOCKET == (sok->skt = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) )  goto sok_error;
    if ( -1 == bind(sok->skt,(struct sockaddr*)&addr,addr_len) ) goto sok_error;
    if ( -1 == listen(sok->skt,(listlen?listlen:SOMAXCONN)) ) goto sok_error;

    if ( sok->skt == INVALID_SOCKET )
      {       
    sok_error: 
        __Raise_Format(YOYO_ERROR_IO,
                        (__yoTa("tcp bind/listen failed: sok %d, point %s:%d, error %s",0)
                        ,sok->skt
                        ,Ip_Format(ip)
                        ,port
                        ,Tcp_Format_Error()));
      }


      
    return sok;
  }
#endif
  ;

#ifdef _YOYO_TCPIP_BUILTIN

void Cbk_Tcp_Accept(YOYO_TCPSOK *sok, YOYO_TCP_IOT *iot, int status)

  {


    if ( !status && !iot->err )
      {
        YOYO_TCPSOK *sok2 = Tcp_Socket();
        sok2->ip   = iot->ip;
        sok2->port = iot->port;
        sok2->skt  = iot->skt;
        iot->cbk(iot->obj,TCP_AIO_COMPLETE,sok2);
      }

    else
      {


        if ( sok->skt == INVALID_SOCKET )
          iot->cbk(iot->obj,TCP_AIO_FAIL|TCP_PERMANENT_ERROR|TCP_IS_CLOSED);
        else
          iot->cbk(iot->obj,TCP_AIO_FAIL);
      }
  }






void Wrk_Tcp_Accept(YOYO_TCP_IOT *iot)
  {
    int skt,addr_len = sizeof(iot->addr);
    
    skt = accept(iot->skt,(struct sockaddr*)&iot->addr,&addr_len);
    

    if ( skt != INVALID_SOCKET )
      {



        iot->ip   = Tcp_Sin_Ip(&iot->addr);
        iot->port = ntohs(iot->addr.addr4.sin_port);
        iot->skt  = skt;
        iot->err  = 0;
        iot->count = addr_len;
      }
    else
      {




        iot->skt = INVALID_SOCKET;



        iot->err = Tcp_Errno();
      }
  }
#endif

void Tcp_Aio_Accept(YOYO_TCPSOK *sok, tcp_accept_callback_t callback, void *obj)
#ifdef _YOYO_TCPIP_BUILTIN
  {
    __Auto_Release
      {
        YOYO_TCP_IOT *iot = Tcp_Alloc_Iot();
        iot->skt = sok->skt;
        iot->cbk = callback;
        iot->obj = __Refe(obj);
        Tasque_Queue(Wrk_Tcp_Accept,iot,Cbk_Tcp_Accept,sok);
      }
  }
#endif
  ;






#define Tcp_Shutdown(Sok) Tcp_Graceful_Close(Sok)




#endif /* C_once_F8F16072_F92E_49E7_A983_54F60965F4C9 */

Changes to tests/httpd.c.

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
..
91
92
93
94
95
96
97
98
99
100
101
102
103

104
105
106
107
108
      "c:|cfg:|config:,"
      "e:|exec_root:,"
      ,PROG_EXIT_ON_ERROR);

    //__Try_Exit(0)
      {
        YOYO_WEBHOST *webhost = Webhost_Init();
        
        __Auto_Release
          {
            int   port = 80;
            char *foo;
            char *host = "127.0.0.1";
            YOYO_XDATA *cfg;
    
................................................................................
            host = Prog_First_Opt("host",host);

            if ( !!(foo = Prog_First_Opt("doc_root",0)) )
              Webhost_Set_Doc_Root(webhost,foo);
            if ( !!(foo = Prog_First_Opt("exec_root",0)) )
              Webhost_Set_Exec_Root(webhost,foo);

            Httpd_Listen(Httpd_Server(webhost,Webhost_Callback),host,port);
          }
          
        while ( Asio_Perform_IO(10,0) )
          {
            ;

          }
      }

    return 0;
  }







|







 







|


|

<
>





63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
..
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
      "c:|cfg:|config:,"
      "e:|exec_root:,"
      ,PROG_EXIT_ON_ERROR);

    //__Try_Exit(0)
      {
        YOYO_WEBHOST *webhost = Webhost_Init();
        quad_t q = Get_System_Millis();
        __Auto_Release
          {
            int   port = 80;
            char *foo;
            char *host = "127.0.0.1";
            YOYO_XDATA *cfg;
    
................................................................................
            host = Prog_First_Opt("host",host);

            if ( !!(foo = Prog_First_Opt("doc_root",0)) )
              Webhost_Set_Doc_Root(webhost,foo);
            if ( !!(foo = Prog_First_Opt("exec_root",0)) )
              Webhost_Set_Exec_Root(webhost,foo);

            Httpd_Listen(Httpd_Server(Webhost_Callback,webhost),host,port);
          }
          
        while ( Tasque_Perform_Update(10,0) )
          {

            //if ( q + 30000 < Get_System_Millis() ) break;
          }
      }

    return 0;
  }

Changes to threads.hc.

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61




62
63
64
65
66
67
68
..
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
..
90
91
92
93
94
95
96










97
98
99
100
101
102
103
104
105
106
107
108
109
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
211
212
213
214
215
216
217
218








































































































































219

*/


#ifndef C_once_7BF4D1A1_7ED4_4CFB_AA04_0E72090D6614
#define C_once_7BF4D1A1_7ED4_4CFB_AA04_0E72090D6614

#ifdef _LIBYOYO
#define _YOYO_THREADS_BUILTIN
#endif

#include "yoyo.hc"

#ifdef __windoze
typedef HANDLE thread_t;
#define INVALID_THREAD_VALIUE ((HANDLE)0)
#else
typedef pthread_t thread_t;
#endif





enum 
  {
    THREAD_STILL_ACTIVE = -1,
  };

typedef void (*thread_func_t)(void*);
................................................................................
    thread_func_t func;
    void *o;    
  } YOYO_THREAD_COOKIE;
static _Thread_Release_Cookie(YOYO_THREAD_COOKIE *cookie) 
  {
    free(cookie);
  }
static YOYO_THREAD_COOKIE *_Thread_Allocate_Cookie(thread_func_t func,void *o) 
  {
    YOYO_THREAD_COOKIE *cookie = malloc(sizeof(YOYO_THREAD_COOKIE));
    cookie->func = func;
    cookie->o = o;
    return cookie;
  }
static DWORD __stdcall _Thread_Proc(YOYO_THREAD_COOKIE *cookie)
................................................................................
    void *o = cookie->o;    
    free(cookie);
    func(o);
    return 0;
  }
#endif











thread_t Thread_Run(thread_func_t func,void *o)
#ifdef _YOYO_THREADS_BUILTIN
  {
    YOYO_THREAD_COOKIE *cookie = _Thread_Allocate_Cookie(func,o);
  #ifdef __windoze
    thread_t thr = CreateThread(0,0,_Thread_Proc,cookie,0,0);
    if ( thr == INVALID_THREAD_VALIUE )
      _Thread_Release_Cookie(cookie);
    return thr;
  #else
  #endif
  }
#endif
................................................................................
static void __No_Return _Thread_Raise_Error()
  {
    __Raise_System_Error();
  }
#endif
    
/* be sure thread is running */
thread_t Thread_Run_Sure(thread_func_t func,void *o)
#ifdef _YOYO_THREADS_BUILTIN
  {
    thread_t thr = Thread_Run(func,o);
    if ( thr != INVALID_THREAD_VALIUE )
      {
    #ifdef __windoze
        //WaitForSingleObject(thr,INFINITE);
    #else
    #endif  
      }
................................................................................
    else
      _Thread_Raise_Error();
    return thr;
  }
#endif
  ;
  
void Thread_Run_Close(thread_func_t func,void *o)
#ifdef _YOYO_THREADS_BUILTIN
  {
    thread_t thr = Thread_Run(func,o);
    if ( thr != INVALID_THREAD_VALIUE )
      Thread_Close(thr);
    else
      _Thread_Raise_Error();
  }
#endif
  ;
................................................................................
        CloseHandle(thr);
      #else
      #endif
      }
  } 
#endif
  ;
  








































































































































#endif /*C_once_7BF4D1A1_7ED4_4CFB_AA04_0E72090D6614*/







<
<
<
<








>
>
>
>







 







|







 







>
>
>
>
>
>
>
>
>
>
|




|







 







|


|







 







|


|







 







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

43
44
45
46
47
48
49




50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365

*/


#ifndef C_once_7BF4D1A1_7ED4_4CFB_AA04_0E72090D6614
#define C_once_7BF4D1A1_7ED4_4CFB_AA04_0E72090D6614





#include "yoyo.hc"

#ifdef __windoze
typedef HANDLE thread_t;
#define INVALID_THREAD_VALIUE ((HANDLE)0)
#else
typedef pthread_t thread_t;
#endif

#ifdef _LIBYOYO
#define _YOYO_THREADS_BUILTIN
#endif

enum 
  {
    THREAD_STILL_ACTIVE = -1,
  };

typedef void (*thread_func_t)(void*);
................................................................................
    thread_func_t func;
    void *o;    
  } YOYO_THREAD_COOKIE;
static _Thread_Release_Cookie(YOYO_THREAD_COOKIE *cookie) 
  {
    free(cookie);
  }
static YOYO_THREAD_COOKIE *_Thread_Allocate_Cookie(thread_func_t func, void *o) 
  {
    YOYO_THREAD_COOKIE *cookie = malloc(sizeof(YOYO_THREAD_COOKIE));
    cookie->func = func;
    cookie->o = o;
    return cookie;
  }
static DWORD __stdcall _Thread_Proc(YOYO_THREAD_COOKIE *cookie)
................................................................................
    void *o = cookie->o;    
    free(cookie);
    func(o);
    return 0;
  }
#endif

thread_t Thread_Get_Current()
#ifdef _YOYO_THREADS_BUILTIN
  {
  #ifdef __windoze
    return GetCurrentThread();
  #else
  #endif
  }
#endif;

thread_t Thread_Run(thread_func_t func, void *o, int stacksize)
#ifdef _YOYO_THREADS_BUILTIN
  {
    YOYO_THREAD_COOKIE *cookie = _Thread_Allocate_Cookie(func,o);
  #ifdef __windoze
    thread_t thr = CreateThread(0,stacksize,_Thread_Proc,cookie,0,0);
    if ( thr == INVALID_THREAD_VALIUE )
      _Thread_Release_Cookie(cookie);
    return thr;
  #else
  #endif
  }
#endif
................................................................................
static void __No_Return _Thread_Raise_Error()
  {
    __Raise_System_Error();
  }
#endif
    
/* be sure thread is running */
thread_t Thread_Run_Sure(thread_func_t func, void *o, int stacksize)
#ifdef _YOYO_THREADS_BUILTIN
  {
    thread_t thr = Thread_Run(func,o,stacksize);
    if ( thr != INVALID_THREAD_VALIUE )
      {
    #ifdef __windoze
        //WaitForSingleObject(thr,INFINITE);
    #else
    #endif  
      }
................................................................................
    else
      _Thread_Raise_Error();
    return thr;
  }
#endif
  ;
  
void Thread_Run_Close(thread_func_t func, void *o, int stacksize)
#ifdef _YOYO_THREADS_BUILTIN
  {
    thread_t thr = Thread_Run(func,o,stacksize);
    if ( thr != INVALID_THREAD_VALIUE )
      Thread_Close(thr);
    else
      _Thread_Raise_Error();
  }
#endif
  ;
................................................................................
        CloseHandle(thr);
      #else
      #endif
      }
  } 
#endif
  ;
     
#ifdef __windoze

typedef struct _YOYO_THRSYNC
  {
    CRITICAL_SECTION *cs;
    HANDLE notify;
  } YOYO_THRSYNC;
  
void Thrsync_Free(YOYO_THRSYNC *l)
#ifdef _YOYO_THREADS_BUILTIN
  {
    if ( l->cs )
      {
        DeleteCriticalSection(l->cs);
        free(l->cs);
        l->cs = 0;
      }
    if ( l->notify )
      {
        CloseHandle(l->notify);
        l->notify = 0;
      }
  }
#endif
  ;

void Thrsync_Init_CS(CRITICAL_SECTION * volatile *cs)
#ifdef _YOYO_THREADS_BUILTIN
  {
    CRITICAL_SECTION *ccs = malloc(sizeof(CRITICAL_SECTION));
    InitializeCriticalSection(ccs);
    if ( 0 != InterlockedCompareExchangePointer(cs,ccs,0) )
      {
        DeleteCriticalSection(ccs);
        free(ccs);
      }
  }
#endif
  ;
  
void Thrsync_Init_Notify(HANDLE volatile *notify)
#ifdef _YOYO_THREADS_BUILTIN
  {
    HANDLE h = CreateEvent(0,0,0,0);
    if ( 0 != InterlockedCompareExchangePointer(notify,h,0) )
      {
        CloseHandle(h);
      }
  }
#endif
  ;

void Nolock_Wait(YOYO_THRSYNC *l, long ms)
#ifdef _YOYO_THREADS_BUILTIN
  {
    if ( !l->notify ) Thrsync_Init_Notify(&l->notify);
    WaitForSingleObject(l->notify,ms>=0?ms:INFINITE);
  }
#endif
  ;

void Nolock_Notify(YOYO_THRSYNC *l)
#ifdef _YOYO_THREADS_BUILTIN
  {
    if ( !l->notify ) Thrsync_Init_Notify(&l->notify);
    SetEvent(l->notify);
  }
#endif
  ;

void Thrsync_Acquire(YOYO_THRSYNC *l)
#ifdef _YOYO_THREADS_BUILTIN
  {
    if ( !l->cs ) Thrsync_Init_CS(&l->cs);
    EnterCriticalSection(l->cs);
  }
#endif
  ;

void Thrsync_Release(YOYO_THRSYNC *l)
#ifdef _YOYO_THREADS_BUILTIN
  {
    if ( l->cs )
      LeaveCriticalSection(l->cs);
  }
#endif
  ;

void Unlock_Wait_Lock(YOYO_THRSYNC *l, long ms)
#ifdef _YOYO_THREADS_BUILTIN
  {
    Thrsync_Release(l);
    Nolock_Wait(l,ms);
    Thrsync_Acquire(l);
  }
#endif
  ;

void Unlock_Notify_Lock(YOYO_THRSYNC *l)
#ifdef _YOYO_THREADS_BUILTIN
  {
    Thrsync_Release(l);
    Nolock_Notify(l);
    Switch_to_Thread();
    Thrsync_Acquire(l);
  }
#endif
  ;

void YOYO_THRSYNC_Destruct(YOYO_THRSYNC *l)
#ifdef _YOYO_THREADS_BUILTIN
  {
    Thrsync_Free(l);
    __Destruct(l);
  }
#endif
  ;
  
YOYO_THRSYNC *Thrsync_Init()
#ifdef _YOYO_THREADS_BUILTIN
  {
    return __Object_Dtor(sizeof(YOYO_THRSYNC),YOYO_THRSYNC_Destruct);
  }
#endif
  ;
  
#define YOYO_THRSYNC_INIT { 0, 0}

/* __windoze way ends here */

#endif 

#define __Thr_Lock(l) \
              __Interlock_Opt(((void)0),l, \
                  Thrsync_Acquire,Thrsync_Release,Thrsync_Release)

#endif /*C_once_7BF4D1A1_7ED4_4CFB_AA04_0E72090D6614*/

Changes to webget.hc.

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
              {
                if ( webget->callback )
                  webget->callback(webget->cbkobj,WEBGET_FINISHED,0,webget);
              }
          }
        else if ( webget->ondemand )
          {
            Asio_Alert(0,wrk,Cbk_Webget_Alert_Callback);
          } 
      }
    else
      { 
        YOYO_DICTO *hdrs = Httpx_Hdrs_Set_Range(0,wrk->offs,wrk->len);
        wrk->bf->count = 0;
        Httpx_Query(httpx,HTTPX_GET,0,hdrs,0,Buffer_As_File(wrk->bf),st->h.block_size);







|







472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
              {
                if ( webget->callback )
                  webget->callback(webget->cbkobj,WEBGET_FINISHED,0,webget);
              }
          }
        else if ( webget->ondemand )
          {
            Tasque_Alert(0,Cbk_Webget_Alert_Callback,wrk);
          } 
      }
    else
      { 
        YOYO_DICTO *hdrs = Httpx_Hdrs_Set_Range(0,wrk->offs,wrk->len);
        wrk->bf->count = 0;
        Httpx_Query(httpx,HTTPX_GET,0,hdrs,0,Buffer_As_File(wrk->bf),st->h.block_size);

Changes to webhost.hc.

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
    st->script = script;
    st->pathinfo = pathinfo;
    return st;
  }
#endif
  ;
    
void Webhost_Check_CGI_Status(YOYO_WEBHOST_CGIST *st, int status)
#ifdef _YOYO_WEBHOST_BUILTIN
  {
    int retcode = 0;
    
    if ( !ASIO_ST_SUCCEEDED(status) ) return;
    
    __Auto_Release 
      {
        __Try_Except
          {
            if (  Pipex_Exit_Code(st->pipex) == PIPEX_STILL_ACTIVE )
              {
                Asio_Alert(0,st,Webhost_Check_CGI_Status);
              }
            else
              if ( st->pipex->exitcode == 0 )
                {
                  YOYO_HTTPD_REQUEST *rqst = st->rqst;
                  YOYO_BUFFER *bf = Buffer_Init(0);
                  YOYO_BUFFER_FILE *fbf = Buffer_As_File(bf);
................................................................................
            if ( st->rqst->instrm )
              {
                int c = Oj_Copy_File(st->rqst->instrm,st->pipex->fin);
                Oj_Flush(st->pipex->fin);
                Oj_Close(st->pipex->fin);
              }
              
            Asio_Alert(0,st,Webhost_Check_CGI_Status);
            retcode = 0;
          }
        __Except
          {
            Log_Error("[ERR/EXCEPTION] %s\n%s",__Format_Error(),__Format_Error_Btrace());
            retcode = 500;
          }
................................................................................
                /* list directory */
                if ( !host->disable_index )
                  {
                    YOYO_BUFFER *obf = Buffer_Init(0);
                    YOYO_ARRAY *L = File_List_Directory(path,0);
                    for ( i = 0; i < L->count; ++i )
                      {
                        Buffer_Printf(obf,"<a href=\"%s/%s\">%s</a><br>",url->query,L->at[i],L->at[i]);
                      }
                    rqst->outstrm = __Refe(Buffer_As_File(obf));
                    rqst->outstrm_length = obf->count;
                    rqst->outstrm_type = Mime_String_Of_Npl(YOYO_MIME_HTML);
                    return HTTPD_SUCCESS;
                  }
                return HTTPD_NOTFOUND;







|




|







|







 







|







 







|







361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
    st->script = script;
    st->pathinfo = pathinfo;
    return st;
  }
#endif
  ;
    
void Webhost_Check_CGI_Status(YOYO_WEBHOST_CGIST *st, int error)
#ifdef _YOYO_WEBHOST_BUILTIN
  {
    int retcode = 0;
    
    if ( error ) return;
    
    __Auto_Release 
      {
        __Try_Except
          {
            if (  Pipex_Exit_Code(st->pipex) == PIPEX_STILL_ACTIVE )
              {
                Tasque_Alert(0,Webhost_Check_CGI_Status,st);
              }
            else
              if ( st->pipex->exitcode == 0 )
                {
                  YOYO_HTTPD_REQUEST *rqst = st->rqst;
                  YOYO_BUFFER *bf = Buffer_Init(0);
                  YOYO_BUFFER_FILE *fbf = Buffer_As_File(bf);
................................................................................
            if ( st->rqst->instrm )
              {
                int c = Oj_Copy_File(st->rqst->instrm,st->pipex->fin);
                Oj_Flush(st->pipex->fin);
                Oj_Close(st->pipex->fin);
              }
              
            Tasque_Alert(0,Webhost_Check_CGI_Status,st);
            retcode = 0;
          }
        __Except
          {
            Log_Error("[ERR/EXCEPTION] %s\n%s",__Format_Error(),__Format_Error_Btrace());
            retcode = 500;
          }
................................................................................
                /* list directory */
                if ( !host->disable_index )
                  {
                    YOYO_BUFFER *obf = Buffer_Init(0);
                    YOYO_ARRAY *L = File_List_Directory(path,0);
                    for ( i = 0; i < L->count; ++i )
                      {
                        Buffer_Printf(obf,"<a href=\"%s%s\">%s</a><br>",url->query,L->at[i],L->at[i]);
                      }
                    rqst->outstrm = __Refe(Buffer_As_File(obf));
                    rqst->outstrm_length = obf->count;
                    rqst->outstrm_type = Mime_String_Of_Npl(YOYO_MIME_HTML);
                    return HTTPD_SUCCESS;
                  }
                return HTTPD_NOTFOUND;

Changes to yoyo.hc.

382
383
384
385
386
387
388






389
390
391
392
393
394
395
...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
...
458
459
460
461
462
463
464



































































465
466
467
468
469
470
471
....
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
....
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118

1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
....
1187
1188
1189
1190
1191
1192
1193


















































































1194
1195























1196
1197
1198
1199
1200
1201
1202
1203
1204
1205

1206
1207
1208
1209
1210
1211
1212
....
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
....
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
....
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
    YO_RAISE_ERROR            = 0x70000000,
    YO_PRINT_FLUSH            = 1,
    YO_PRINT_NEWLINE          = 2,
  };

__No_Return void _Yo_Fatal(int err,void *ctx,char *filename,int lineno);
__No_Return void _Yo_Raise(int err,char *msg,char *filename,int lineno);







#ifndef _THREADS

# define Yo_Atomic_Increment(Ptr) (++*(Ptr))
# define Yo_Atomic_Decrement(Ptr) (--*(Ptr))
# define Yo_Atomic_CmpXchg(Ptr,Val,Comp) ( *(Ptr) == (Comp) ? (*(Ptr) = (Val), 1) : 0 )
# define Yo_Atomic_CmpXchg_Ptr(Ptr,Val,Comp) ( *(Ptr) == (Comp) ? (*(Ptr) = (Val), 1) : 0 )
................................................................................
              __Interlock_Opt( _xchg_YOYO_LOCAL_LX, _xchg_YOYO_LOCAL_ID_REF, \
                  Yo_Wait_Xchg_Lock,Yo_Xchg_Unlock,Yo_Xchg_Unlock_Proc)

# define __Xchg_Sync(Lx) \
              __Interlock_Opt(((void)0),Lx, \
                  Yo_Wait_Xchg_Lock,Yo_Xchg_Unlock,Yo_Xchg_Unlock_Proc)

# define Yo_Wait_Xchg_Lock(Ptr) while ( !Yo_Atomic_CmpXchg(Ptr,1,0) ) Yo_Switch_to_Thread()
# define Yo_Xchg_Unlock(Ptr) Yo_Atomic_CmpXchg(Ptr,0,1)

void Yo_Xchg_Unlock_Proc(int volatile *p) _YOYO_CORE_BUILTIN_CODE({Yo_Atomic_CmpXchg(p,0,1);});

# define __Mtx_Sync(Mtx) \
              __Interlock_Opt(((void)0),Mtx, \
                  Yo_Wait_Mtx_Lock,Yo_Mtx_Unlock,Yo_Mtx_Unlock_Proc)

#endif

#if defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__>=6) )
  #define __Static_Assert_S(expr,S) _Static_assert(expr,S)
#elif !defined _MSC_VER || _MSC_VER < 1600 || defined __ICL
  #define __Static_Assert_S(expr,S) \
    extern char YOYO_LOCAL_ID(__assert__)[(expr)?1:-1]
#else
  #define __Static_Assert_S(expr,S) static_assert(expr,S)
................................................................................
#ifdef _STRICT
# define STRICT_REQUIRE(Expr) REQUIRE(Expr)
# define STRICT_CHECK(Expr) (Expr)
#else
# define STRICT_REQUIRE(Expr) ((void)0)
# define STRICT_CHECK(Expr) (1)
#endif /* _STRICT */




































































#if defined __i386 || defined __x86_64
#define Eight_To_Quad(Eight)  (*(quad_t*)(Eight))
#else
quad_t Eight_To_Quad(void *b)
#ifdef _YOYO_CORE_BUILTIN
  {
................................................................................
int _vscprintf(char *fmt,va_list va)
  {
    static char simulate[4096*4] = {0};
    return vsprintf(simulate,fmt,va);
  }
#endif


int Yo_Detect_Required_Buffer_Size(char *fmt,va_list va)
#ifdef _YOYO_CORE_BUILTIN
  {
  #ifdef __windoze
    return _vscprintf(fmt,va)+1;
  #else
    va_list qva;
................................................................................
    longptr_t typeid;
    YOYO_FUNCTABLE funcs[1];
  }
  YOYO_DYNAMIC;

typedef struct _YOYO_CORE_OBJECT
  {
    YOYO_DYNAMIC *dynamic;
    uint_t signature; /* YOYO_OBJECT_SIGNATURE */
    uint_t rc;

  }
  YOYO_OBJECT;

#define YOYO_BASE(Ptr)          ((YOYO_OBJECT*)(Ptr) - 1)
#define YOYO_RC(Ptr)            (YOYO_BASE(Ptr)->rc)
#define YOYO_SIGNAT(Ptr)        (YOYO_BASE(Ptr)->signature)
#define YOYO_SIGNAT_IS_OK(Ptr)  ((YOYO_BASE(Ptr)->signature)==YOYO_OBJECT_SIGNATURE)

void *Yo_Unrefe(void *p);

#ifdef _YOYO_CORE_BUILTIN
uint_t Yo_Typeid_Counter = 0;
#endif

................................................................................
    f->func = func;

    return o;
  }
#endif
  ;



















































































enum { YOYO_OBJECT_SIGNATURE =  0x4f594f59 /*'YOYO'*/  };
























void *Yo_Object_Clone(int size, void *orign)
#ifdef _YOYO_CORE_BUILTIN
  {
    YOYO_OBJECT *o;
    YOYO_OBJECT *T = YOYO_BASE(orign);
    if ( !T )
      Yo_Raise(YOYO_ERROR_NULL_PTR,__yoTa("failed to clone nullptr",0),__Yo_FILE__,__LINE__);

    o = Yo_Malloc_Npl(sizeof(YOYO_OBJECT)+size);
    o->signature = YOYO_OBJECT_SIGNATURE;

    o->rc = 1;
    memcpy(o+1,orign,size);

    if ( T->dynamic )
      {
        if ( (T->dynamic->contsig>>8) == YOYO_DYNCO_ATS )
          o->dynamic = T->dynamic;
................................................................................
  }
#endif
  ;

void *Yo_Object(int size,YOYO_FUNCTABLE *tbl)
#ifdef _YOYO_CORE_BUILTIN
  {
    YOYO_OBJECT *o = Yo_Zero_Malloc_Npl(sizeof(YOYO_OBJECT)+size);
    o->signature = YOYO_OBJECT_SIGNATURE;
    o->rc = 1;
    o->dynamic = (YOYO_DYNAMIC*)tbl;

    if ( tbl )
      {__Xchg_Interlock
        {
          YOYO_DYNAMIC *dynco = (YOYO_DYNAMIC*)tbl;
................................................................................
#endif
  ;

void *Yo_Object_Dtor(int size,void *dtor)
#ifdef _YOYO_CORE_BUILTIN
  {
    int Sz = Yo_Align(sizeof(YOYO_OBJECT)+size);
    YOYO_OBJECT *o = Yo_Zero_Malloc_Npl(Sz+sizeof(YOYO_DYNAMIC));
    o->signature = YOYO_OBJECT_SIGNATURE;
    o->rc = 1;
    o->dynamic = (YOYO_DYNAMIC*)((char*)o + Sz);
    o->dynamic->contsig = (YOYO_DYNCO_ATS<<8)|1;
    o->dynamic->funcs[0].name = Oj_Destruct_OjMID;
    o->dynamic->funcs[0].func = dtor;
    o->dynamic->typeid = Yo_Atomic_Increment(&Yo_Typeid_Counter);
    return Yo_Pool_Ptr(o+1,Yo_Unrefe);
................................................................................
  {
    if ( ptr )
      {
        YOYO_OBJECT *o = (YOYO_OBJECT *)ptr - 1;
        if ( o->dynamic && (o->dynamic->contsig>>8) == YOYO_DYNCO_NYD )
          free(o->dynamic);
        o->dynamic = 0;
        free(o);
      }
  }
#endif
  ;

void *Yo_Find_Method_In_Table(char *name,YOYO_FUNCTABLE *tbl,int count,int flags)
#ifdef _YOYO_CORE_BUILTIN







>
>
>
>
>
>







 







|




|

|


|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<







 







<


>






|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








<
<
>







 







|
<







 







|
<







 







|







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
...
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
....
1112
1113
1114
1115
1116
1117
1118

1119
1120
1121
1122
1123
1124
1125
....
1181
1182
1183
1184
1185
1186
1187

1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
....
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380


1381
1382
1383
1384
1385
1386
1387
1388
....
1399
1400
1401
1402
1403
1404
1405
1406

1407
1408
1409
1410
1411
1412
1413
....
1433
1434
1435
1436
1437
1438
1439
1440

1441
1442
1443
1444
1445
1446
1447
....
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
    YO_RAISE_ERROR            = 0x70000000,
    YO_PRINT_FLUSH            = 1,
    YO_PRINT_NEWLINE          = 2,
  };

__No_Return void _Yo_Fatal(int err,void *ctx,char *filename,int lineno);
__No_Return void _Yo_Raise(int err,char *msg,char *filename,int lineno);

#ifdef __windoze
#define Switch_to_Thread() SwitchToThread()
#else
#define Switch_to_Thread() ((void)0)
#endif

#ifndef _THREADS

# define Yo_Atomic_Increment(Ptr) (++*(Ptr))
# define Yo_Atomic_Decrement(Ptr) (--*(Ptr))
# define Yo_Atomic_CmpXchg(Ptr,Val,Comp) ( *(Ptr) == (Comp) ? (*(Ptr) = (Val), 1) : 0 )
# define Yo_Atomic_CmpXchg_Ptr(Ptr,Val,Comp) ( *(Ptr) == (Comp) ? (*(Ptr) = (Val), 1) : 0 )
................................................................................
              __Interlock_Opt( _xchg_YOYO_LOCAL_LX, _xchg_YOYO_LOCAL_ID_REF, \
                  Yo_Wait_Xchg_Lock,Yo_Xchg_Unlock,Yo_Xchg_Unlock_Proc)

# define __Xchg_Sync(Lx) \
              __Interlock_Opt(((void)0),Lx, \
                  Yo_Wait_Xchg_Lock,Yo_Xchg_Unlock,Yo_Xchg_Unlock_Proc)

# define Yo_Wait_Xchg_Lock(Ptr) while ( !Yo_Atomic_CmpXchg(Ptr,1,0) ) Switch_to_Thread()
# define Yo_Xchg_Unlock(Ptr) Yo_Atomic_CmpXchg(Ptr,0,1)

void Yo_Xchg_Unlock_Proc(int volatile *p) _YOYO_CORE_BUILTIN_CODE({Yo_Atomic_CmpXchg(p,0,1);});

/*# define __Mtx_Sync(Mtx) \
              __Interlock_Opt(((void)0),Mtx, \
                  Yo_Wait_Mtx_Lock,Yo_Mtx_Unlock,Yo_Mtx_Unlock_Proc)*/

#endif
  
#if defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__>=6) )
  #define __Static_Assert_S(expr,S) _Static_assert(expr,S)
#elif !defined _MSC_VER || _MSC_VER < 1600 || defined __ICL
  #define __Static_Assert_S(expr,S) \
    extern char YOYO_LOCAL_ID(__assert__)[(expr)?1:-1]
#else
  #define __Static_Assert_S(expr,S) static_assert(expr,S)
................................................................................
#ifdef _STRICT
# define STRICT_REQUIRE(Expr) REQUIRE(Expr)
# define STRICT_CHECK(Expr) (Expr)
#else
# define STRICT_REQUIRE(Expr) ((void)0)
# define STRICT_CHECK(Expr) (1)
#endif /* _STRICT */

#define Slist_Remove_By(ListPtr,Next,Val) Yo_Slist_Remove(ListPtr,(int)((size_t)(&(*ListPtr)->Next)-(size_t)(*ListPtr)),Val)
#define Slist_Remove(ListPtr,Val) Slist_Remove_By(ListPtr,next,Val)

void Yo_Slist_Remove(void **p, int offs_of_next, void *val)
#ifdef _YOYO_CORE_BUILTIN
  {
    if ( p ) 
      {
        while ( *p )
          {
            if ( *p == val )
              {
                void *r = *p;
                *p = *(void**)((byte_t*)r + offs_of_next);
                *(void**)((byte_t*)r + offs_of_next) = 0;
                break;
              }
            else
              p =  (void**)((byte_t*)*p + offs_of_next);
          }
      }
  }
#endif
  ;

#define Slist_Push_By(ListPtr,Next,Val) Yo_Slist_Push(ListPtr,(int)((size_t)(&(*ListPtr)->Next)-(size_t)(*ListPtr)),Val)
#define Slist_Push(ListPtr,Val) Slist_Push_By(ListPtr,next,Val)

void Yo_Slist_Push(void **p, int offs_of_next, void *val)
#ifdef _YOYO_CORE_BUILTIN
  {
    if ( p ) 
      {
        while ( *p )
          {
            p =  (void**)((byte_t*)*p + offs_of_next);
          }
        *p = val;
        *(void**)((byte_t*)*p + offs_of_next) = 0;
      }
  }
#endif
  ;
  
#define Slist_Pop_By(ListPtr,Next) Yo_Slist_Pop(ListPtr,(int)((size_t)(&(*ListPtr)->Next)-(size_t)(*ListPtr)))
#define Slist_Pop(ListPtr) Slist_Pop_By(ListPtr,next)

void *Yo_Slist_Pop(void **p, int offs_of_next)
#ifdef _YOYO_CORE_BUILTIN
  {
    void *r = 0;
    
    if ( p )
      {
        r = *p;
        if ( r ) 
          {
            *p = *(void**)((byte_t*)r + offs_of_next);
            *(void**)((byte_t*)r + offs_of_next) = 0;
          }
      }
      
    return r;
  }
#endif
  ;

#if defined __i386 || defined __x86_64
#define Eight_To_Quad(Eight)  (*(quad_t*)(Eight))
#else
quad_t Eight_To_Quad(void *b)
#ifdef _YOYO_CORE_BUILTIN
  {
................................................................................
int _vscprintf(char *fmt,va_list va)
  {
    static char simulate[4096*4] = {0};
    return vsprintf(simulate,fmt,va);
  }
#endif


int Yo_Detect_Required_Buffer_Size(char *fmt,va_list va)
#ifdef _YOYO_CORE_BUILTIN
  {
  #ifdef __windoze
    return _vscprintf(fmt,va)+1;
  #else
    va_list qva;
................................................................................
    longptr_t typeid;
    YOYO_FUNCTABLE funcs[1];
  }
  YOYO_DYNAMIC;

typedef struct _YOYO_CORE_OBJECT
  {

    uint_t signature; /* YOYO_OBJECT_SIGNATURE */
    uint_t rc;
    YOYO_DYNAMIC *dynamic;
  }
  YOYO_OBJECT;

#define YOYO_BASE(Ptr)          ((YOYO_OBJECT*)(Ptr) - 1)
#define YOYO_RC(Ptr)            (YOYO_BASE(Ptr)->rc)
#define YOYO_SIGNAT(Ptr)        (YOYO_BASE(Ptr)->signature)
#define YOYO_SIGNAT_IS_OK(Ptr)  ((YOYO_BASE(Ptr)->signature&0x00ffffff) == YOYO_OBJECT_SIGNATURE_PFX)

void *Yo_Unrefe(void *p);

#ifdef _YOYO_CORE_BUILTIN
uint_t Yo_Typeid_Counter = 0;
#endif

................................................................................
    f->func = func;

    return o;
  }
#endif
  ;

enum 
  { 
    YOYO_OBJECT_SIGNATURE_PFX  =  0x00594f59, /*'YOY'*/  
    YOYO_OBJECT_SIGNATURE_HEAP =  0x4f594f59, /*'YOYO'*/  
    YOYO_MEMPOOL_PIECE_MAXSIZE = 1*KILOBYTE,
    YOYO_MEMPOOL_PIECE_ON_BLOCK= 16,
    YOYO_MEMPOOL_PIECE_STEP    = 64,
    YOYO_MEMPOOL_SLOTS_COUNT   = YOYO_MEMPOOL_PIECE_MAXSIZE/YOYO_MEMPOOL_PIECE_STEP,
  };

__Static_Assert(YOYO_MEMPOOL_SLOTS_COUNT <= 'O');

#ifdef _YOYO_CORE_BUILTIN
void *Yo_Mempool_Slots[YOYO_MEMPOOL_SLOTS_COUNT] = {0,};
int Yo_Mempool_Counts[YOYO_MEMPOOL_SLOTS_COUNT] = {0,};
#endif

void Yo_Mempool_Free(void *p,int plidx)
#ifdef _YOYO_CORE_BUILTIN
  {
    void **Q = p;
    STRICT_REQUIRE(plidx >= 0 && plidx <YOYO_MEMPOOL_SLOTS_COUNT); 
    for (;;)
      {
        void * volatile *S = Yo_Mempool_Slots+plidx;
        *Q = *S;
        if ( Yo_Atomic_CmpXchg_Ptr(S,Q,*Q) ) break;
      }
  }
#endif
  ;
  
void Yo_Mempool_Extend(int plidx)
#ifdef _YOYO_CORE_BUILTIN
  {
    __Xchg_Interlock
      {
        void * volatile *S = Yo_Mempool_Slots+plidx;
        if ( !*S )
          {
            int i,piece = (plidx+1)*YOYO_MEMPOOL_PIECE_STEP; 
            void **Q = Yo_Malloc_Npl(piece*YOYO_MEMPOOL_PIECE_ON_BLOCK);
            Yo_Mempool_Counts[plidx] += YOYO_MEMPOOL_PIECE_ON_BLOCK;
            for ( i=0; i < YOYO_MEMPOOL_PIECE_ON_BLOCK; ++i, Q = (void**)((byte_t*)Q + piece) )
              for (;;)
                {
                  *Q = *S;
                  if ( Yo_Atomic_CmpXchg_Ptr(S,Q,*Q) ) break;
                }
          }
      }
  }
#endif
  ;
  
void *Yo_Mempool_Zalloc(int plidx)
#ifdef _YOYO_CORE_BUILTIN
  {
    void **Q;
    STRICT_REQUIRE(plidx >= 0 && plidx <YOYO_MEMPOOL_SLOTS_COUNT); 
    for (;;)
      {
        void * volatile *S = Yo_Mempool_Slots+plidx;
        Q = *S;
        if ( !Q ) 
          Yo_Mempool_Extend(plidx);
        else
          if ( Yo_Atomic_CmpXchg_Ptr(S,*Q,Q) ) break;
      }
    memset(Q,0,(plidx+1)*YOYO_MEMPOOL_PIECE_STEP);
    return Q;              
  }
#endif
  ;

YOYO_OBJECT *Yo_Object_Alloc(int size)
#ifdef _YOYO_CORE_BUILTIN
  {
    YOYO_OBJECT *o;
    if ( size + sizeof(YOYO_OBJECT) > YOYO_MEMPOOL_PIECE_MAXSIZE )
      {
        o = Yo_Zero_Malloc_Npl(sizeof(YOYO_OBJECT)+size);
        o->signature = YOYO_OBJECT_SIGNATURE_HEAP;
      }
    else
      {
        int plidx = (sizeof(YOYO_OBJECT)+size-1)/YOYO_MEMPOOL_PIECE_STEP;
        o = Yo_Mempool_Zalloc(plidx);
        o->signature = YOYO_OBJECT_SIGNATURE_PFX + (plidx<<24);
      }
    return o;
  }
#endif
  ;

void Yo_Object_Free(YOYO_OBJECT *o)
#ifdef _YOYO_CORE_BUILTIN
  {
    int plidx = o->signature >> 24;
    if ( plidx >= YOYO_MEMPOOL_SLOTS_COUNT ) 
      free(o);
    else
      Yo_Mempool_Free(o,plidx);
  }
#endif
  ;

void *Yo_Object_Clone(int size, void *orign)
#ifdef _YOYO_CORE_BUILTIN
  {
    YOYO_OBJECT *o;
    YOYO_OBJECT *T = YOYO_BASE(orign);
    if ( !T )
      Yo_Raise(YOYO_ERROR_NULL_PTR,__yoTa("failed to clone nullptr",0),__Yo_FILE__,__LINE__);



    o = Yo_Object_Alloc(size);
    o->rc = 1;
    memcpy(o+1,orign,size);

    if ( T->dynamic )
      {
        if ( (T->dynamic->contsig>>8) == YOYO_DYNCO_ATS )
          o->dynamic = T->dynamic;
................................................................................
  }
#endif
  ;

void *Yo_Object(int size,YOYO_FUNCTABLE *tbl)
#ifdef _YOYO_CORE_BUILTIN
  {
    YOYO_OBJECT *o = Yo_Object_Alloc(size);

    o->rc = 1;
    o->dynamic = (YOYO_DYNAMIC*)tbl;

    if ( tbl )
      {__Xchg_Interlock
        {
          YOYO_DYNAMIC *dynco = (YOYO_DYNAMIC*)tbl;
................................................................................
#endif
  ;

void *Yo_Object_Dtor(int size,void *dtor)
#ifdef _YOYO_CORE_BUILTIN
  {
    int Sz = Yo_Align(sizeof(YOYO_OBJECT)+size);
    YOYO_OBJECT *o = Yo_Object_Alloc(Sz+sizeof(YOYO_DYNAMIC));

    o->rc = 1;
    o->dynamic = (YOYO_DYNAMIC*)((char*)o + Sz);
    o->dynamic->contsig = (YOYO_DYNCO_ATS<<8)|1;
    o->dynamic->funcs[0].name = Oj_Destruct_OjMID;
    o->dynamic->funcs[0].func = dtor;
    o->dynamic->typeid = Yo_Atomic_Increment(&Yo_Typeid_Counter);
    return Yo_Pool_Ptr(o+1,Yo_Unrefe);
................................................................................
  {
    if ( ptr )
      {
        YOYO_OBJECT *o = (YOYO_OBJECT *)ptr - 1;
        if ( o->dynamic && (o->dynamic->contsig>>8) == YOYO_DYNCO_NYD )
          free(o->dynamic);
        o->dynamic = 0;
        Yo_Object_Free(o);
      }
  }
#endif
  ;

void *Yo_Find_Method_In_Table(char *name,YOYO_FUNCTABLE *tbl,int count,int flags)
#ifdef _YOYO_CORE_BUILTIN