Fossil

Check-in [8dd05c52]
Login

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

Overview
Comment:Rework server sockets to work around limitations in OpenBSD's socket implementation. See forum thread 7f8d2afe4d8c0ad5.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8dd05c52f5fac7a84b2f162e6de0b66e9e33378550ebf258abb4c0dd21173158
User & Date: drh 2025-04-17 15:08:47.659
Context
2025-04-17
18:17
Attempt to fix repolist so that it works even if the global configuration database is not available, for example when Fossil is being run inside a chroot jail with a restricted environment. ... (check-in: e761c1d6 user: drh tags: trunk)
15:08
Rework server sockets to work around limitations in OpenBSD's socket implementation. See forum thread 7f8d2afe4d8c0ad5. ... (check-in: 8dd05c52 user: drh tags: trunk)
13:43
Extend support for the --editor option to "fossil stash save" and "fossil stash snapshot". ... (check-in: b9f569b2 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/cgi.c.
2566
2567
2568
2569
2570
2571
2572

2573
2574
2575
2576

2577
2578
2579
2580
2581
2582
2583
  int nRequest = 0;            /* Number of requests handled so far */
  fd_set readfds;              /* Set of file descriptors for select() */
  socklen_t lenaddr;           /* Length of the inaddr structure */
  int child;                   /* PID of the child process */
  int nchildren = 0;           /* Number of child processes */
  struct timeval delay;        /* How long to wait inside select() */
  struct sockaddr_in6 inaddr;  /* The socket address */

  struct sockaddr_un uxaddr;   /* The address for unix-domain sockets */
  int opt = 1;                 /* setsockopt flag */
  int rc;                      /* Result code from system calls */
  int iPort = mnPort;          /* Port to try to use */


  while( iPort<=mxPort ){
    if( flags & HTTP_SERVER_UNIXSOCKET ){
      /* Initialize a Unix socket named g.zSockName */
      assert( g.zSockName!=0 );
      memset(&uxaddr, 0, sizeof(uxaddr));
      if( strlen(g.zSockName)>sizeof(uxaddr.sun_path) ){







>




>







2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
  int nRequest = 0;            /* Number of requests handled so far */
  fd_set readfds;              /* Set of file descriptors for select() */
  socklen_t lenaddr;           /* Length of the inaddr structure */
  int child;                   /* PID of the child process */
  int nchildren = 0;           /* Number of child processes */
  struct timeval delay;        /* How long to wait inside select() */
  struct sockaddr_in6 inaddr;  /* The socket address */
  struct sockaddr_in inaddr4;  /* IPv4 address; needed by OpenBSD */
  struct sockaddr_un uxaddr;   /* The address for unix-domain sockets */
  int opt = 1;                 /* setsockopt flag */
  int rc;                      /* Result code from system calls */
  int iPort = mnPort;          /* Port to try to use */
  int bIPv4 = 0;               /* Use IPv4 only; use inaddr4, not inaddr */

  while( iPort<=mxPort ){
    if( flags & HTTP_SERVER_UNIXSOCKET ){
      /* Initialize a Unix socket named g.zSockName */
      assert( g.zSockName!=0 );
      memset(&uxaddr, 0, sizeof(uxaddr));
      if( strlen(g.zSockName)>sizeof(uxaddr.sun_path) ){
2605
2606
2607
2608
2609
2610
2611








2612
2613

2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625

2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637

2638
2639


2640

2641




2642
2643


2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662


2663
2664
2665
2666
2667
2668
2669
      if( g.zSockMode ){
        file_set_mode(g.zSockName, listener, g.zSockMode, 0);
      }else{
        file_set_mode(g.zSockName, listener, "0660", 1);
      }
    }else{
      /* Initialize a TCP/IP socket on port iPort */








      memset(&inaddr, 0, sizeof(inaddr));
      inaddr.sin6_family = AF_INET6;

      if( zIpAddr ){
        /* Bind to the specific IP address given by zIpAddr[] */
        size_t nAddr = strlen(zIpAddr);
        char z4to6[30];
        
        if( nAddr<16 ){
          /* The specified IP address might be in IPv4 notation (ex: 1.2.3.4)
          ** which inet_pton() does not understand.  Convert in into a IPv6
          ** mapping of an IPv4 address: (::FFFF:1.2.3.4) */
          memcpy(z4to6,"::ffff:", 7);
          memcpy(z4to6+7, zIpAddr, nAddr+2);
        }else{

          z4to6[0] = 0;
        }

        /* Convert the zIpAddr text string into an actual IPv6 address */
        if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0
         && (z4to6[0]==0 || inet_pton(AF_INET6, z4to6, &inaddr.sin6_addr)==0)
        ){
          fossil_fatal("not a valid IP address: %s", zIpAddr);
        }
      }else if( flags & HTTP_SERVER_LOCALHOST ){
        /* Bind to the loop-back IP address */
        inet_pton(AF_INET6, "::ffff.127.0.0.1", &inaddr.sin6_addr);

      }else{
        /* Bind to any and all available IP addresses */


        inaddr.sin6_addr = in6addr_any;

      }




      inaddr.sin6_port = htons(iPort);
      listener = socket(AF_INET6, SOCK_STREAM, 0);


      if( listener<0 ){
        iPort++;
        continue;
      }
      allowBothIpV4andV6(listener);
    }

    /* if we can't terminate nicely, at least allow the socket to be reused */
    setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
  
    if( flags & HTTP_SERVER_UNIXSOCKET ){
      rc = bind(listener, (struct sockaddr*)&uxaddr, sizeof(uxaddr));
      /* Set the owner of the socket if requested by --socket-owner.  This
      ** must wait until after bind(), after the filesystem object has been
      ** created.  See https://lkml.org/lkml/2004/11/1/84 and
      ** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */
      if( g.zSockOwner ){
        file_set_owner(g.zSockName, listener, g.zSockOwner);
      }


    }else{
      rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
    }
    if( rc<0 ){
      close(listener);
      iPort++;
      continue;







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

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


>
>

>

>
>
>
>
|
|
>
>




<














>
>







2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625

2626

2627






2628
2629
2630

2631
2632
2633


2634
2635



2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655

2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
      if( g.zSockMode ){
        file_set_mode(g.zSockName, listener, g.zSockMode, 0);
      }else{
        file_set_mode(g.zSockName, listener, "0660", 1);
      }
    }else{
      /* Initialize a TCP/IP socket on port iPort */
      if( (flags & HTTP_SERVER_LOCALHOST)!=0 && zIpAddr==0 ){
        /* Map all loopback to 127.0.0.1, since this is the easiest way
        ** to support OpenBSD and its limitations without burdening
        ** Linux and MacOS with lots of extra code and complication. */
        zIpAddr = "127.0.0.1";
      }
      if( zIpAddr ){
        if( strchr(zIpAddr,':') ){
          memset(&inaddr, 0, sizeof(inaddr));
          inaddr.sin6_family = AF_INET6;
          bIPv4 = 0;
          if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0 ){

            fossil_fatal("not a valid IPv6 address: %s", zIpAddr);

          }






        }else{
          memset(&inaddr4, 0, sizeof(inaddr4));
          inaddr4.sin_family = AF_INET;

          bIPv4 = 1;
          inaddr4.sin_addr.s_addr = inet_addr(zIpAddr);
          if( inaddr4.sin_addr.s_addr == INADDR_NONE ){


            fossil_fatal("not a valid IPv4 address: %s", zIpAddr);
          }



        }
      }else{
        /* Bind to any and all available IP addresses */
        memset(&inaddr, 0, sizeof(inaddr));
        inaddr.sin6_family = AF_INET6;
        inaddr.sin6_addr = in6addr_any;
        bIPv4 = 0;
      }
      if( bIPv4 ){
        inaddr4.sin_port = htons(iPort);
        listener = socket(AF_INET, SOCK_STREAM, 0);
      }else{
        inaddr.sin6_port = htons(iPort);
        listener = socket(AF_INET6, SOCK_STREAM, 0);
        allowBothIpV4andV6(listener);
      }
      if( listener<0 ){
        iPort++;
        continue;
      }

    }

    /* if we can't terminate nicely, at least allow the socket to be reused */
    setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
  
    if( flags & HTTP_SERVER_UNIXSOCKET ){
      rc = bind(listener, (struct sockaddr*)&uxaddr, sizeof(uxaddr));
      /* Set the owner of the socket if requested by --socket-owner.  This
      ** must wait until after bind(), after the filesystem object has been
      ** created.  See https://lkml.org/lkml/2004/11/1/84 and
      ** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */
      if( g.zSockOwner ){
        file_set_owner(g.zSockName, listener, g.zSockOwner);
      }
    }else if( bIPv4 ){
      rc = bind(listener, (struct sockaddr*)&inaddr4, sizeof(inaddr4));
    }else{
      rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
    }
    if( rc<0 ){
      close(listener);
      iPort++;
      continue;