src/standard.c
struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, char **err, const char *pfx)
{
	static struct sockaddr_storage ss;
	struct sockaddr_storage *ret = NULL;
	char *back, *str2;
	char *port1, *port2;
	int portl, porth, porta;

	portl = porth = porta = 0;

	str2 = back = env_expand(strdup(str));
	if (str2 == NULL) {
		memprintf(err, "out of memory in '%s'\n", __FUNCTION__);
		goto out;
	}

	memset(&ss, 0, sizeof(ss));

	if (strncmp(str2, "unix@", 5) == 0) {
		str2 += 5;
		ss.ss_family = AF_UNIX;
	}
	else if (strncmp(str2, "ipv4@", 5) == 0) {
		str2 += 5;
		ss.ss_family = AF_INET;
	}
	else if (strncmp(str2, "ipv6@", 5) == 0) {
		str2 += 5;
		ss.ss_family = AF_INET6;
	}
	else if (*str2 == '/') {
		ss.ss_family = AF_UNIX;
	}
	else
		ss.ss_family = AF_UNSPEC;

	if (ss.ss_family == AF_UNSPEC && strncmp(str2, "fd@", 3) == 0) {
		char *endptr;

		str2 += 3;
		((struct sockaddr_in *)&ss)->sin_addr.s_addr = strtol(str2, &endptr, 10);

		if (!*str2 || *endptr) {
			memprintf(err, "file descriptor '%s' is not a valid integer in '%s'\n", str2, str);
			goto out;
		}

		/* we return AF_UNSPEC if we use a file descriptor number */
		ss.ss_family = AF_UNSPEC;
	}
	else if (ss.ss_family == AF_UNIX) {
		int prefix_path_len;
		int max_path_len;

		/* complete unix socket path name during startup or soft-restart is
		 * <unix_bind_prefix><path>.<pid>.<bak|tmp>
		 */
		prefix_path_len = pfx ? strlen(pfx) : 0;
		max_path_len = (sizeof(((struct sockaddr_un *)&ss)->sun_path) - 1) -
			(prefix_path_len ? prefix_path_len + 1 + 5 + 1 + 3 : 0);

		if (strlen(str2) > max_path_len) {
			memprintf(err, "socket path '%s' too long (max %d)\n", str, max_path_len);
			goto out;
		}

		if (pfx) {
			memcpy(((struct sockaddr_un *)&ss)->sun_path, pfx, prefix_path_len);
			strcpy(((struct sockaddr_un *)&ss)->sun_path + prefix_path_len, str2);
		}
		else {
			strcpy(((struct sockaddr_un *)&ss)->sun_path, str2);
		}
	}
	else { /* IPv4 and IPv6 */
		port1 = strrchr(str2, ':');
		if (port1)
			*port1++ = '\0';
		else
			port1 = "";

		if (str2ip(str2, &ss) == NULL) {
			memprintf(err, "invalid address: '%s' in '%s'\n", str2, str);
			goto out;
		}

		if (isdigit((int)(unsigned char)*port1)) {	/* single port or range */
			port2 = strchr(port1, '-');
			if (port2)
				*port2++ = '\0';
			else
				port2 = port1;
			portl = atoi(port1);
			porth = atoi(port2);
			porta = portl;
		}
		else if (*port1 == '-') { /* negative offset */
			portl = atoi(port1 + 1);
			porta = -portl;
		}
		else if (*port1 == '+') { /* positive offset */
			porth = atoi(port1 + 1);
			porta = porth;
		}
		else if (*port1) { /* other any unexpected char */
			memprintf(err, "invalid character '%c' in port number '%s' in '%s'\n", *port1, port1, str);
			goto out;
		}
		set_host_port(&ss, porta);
	}

	ret = &ss;
 out:
	if (low)
		*low = portl;
	if (high)
		*high = porth;
	free(back);
	return ret;
}
/*
 * Converts <str> to a locally allocated struct sockaddr_storage *, and a port
 * range or offset consisting in two integers that the caller will have to
 * check to find the relevant input format. The following format are supported :
 *
 *   String format           | address |  port  |  low   |  high
 *    addr                   | <addr>  |   0    |   0    |   0
 *    addr:                  | <addr>  |   0    |   0    |   0
 *    addr:port              | <addr>  | <port> | <port> | <port>
 *    addr:pl-ph             | <addr>  |  <pl>  |  <pl>  |  <ph>
 *    addr:+port             | <addr>  | <port> |   0    | <port>
 *    addr:-port             | <addr>  |-<port> | <port> |   0
 *
 * The detection of a port range or increment by the caller is made by
 * comparing <low> and <high>. If both are equal, then port 0 means no port
 * was specified. The caller may pass NULL for <low> and <high> if it is not
 * interested in retrieving port ranges.
 *
 * Note that <addr> above may also be :
 *    - empty ("")  => family will be AF_INET and address will be INADDR_ANY
 *    - "*"         => family will be AF_INET and address will be INADDR_ANY
 *    - "::"        => family will be AF_INET6 and address will be IN6ADDR_ANY
 *    - a host name => family and address will depend on host name resolving.
 *
 * A prefix may be passed in before the address above to force the family :
 *    - "ipv4@"  => force address to resolve as IPv4 and fail if not possible.
 *    - "ipv6@"  => force address to resolve as IPv6 and fail if not possible.
 *    - "unix@"  => force address to be a path to a UNIX socket even if the
 *                  path does not start with a '/'
 *    - "fd@"    => an integer must follow, and is a file descriptor number.
 *
 * Also note that in order to avoid any ambiguity with IPv6 addresses, the ':'
 * is mandatory after the IP address even when no port is specified. NULL is
 * returned if the address cannot be parsed. The <low> and <high> ports are
 * always initialized if non-null, even for non-IP families.
 *
 * If <pfx> is non-null, it is used as a string prefix before any path-based
 * address (typically the path to a unix socket).
 *
 * When a file descriptor is passed, its value is put into the s_addr part of
 * the address when cast to sockaddr_in and the address family is AF_UNSPEC.
 */
Converts  to a locally allocated struct sockaddr_storage *, and a port
range or offset consisting in two integers that the caller will have to
check to find the relevant input format. The following format are supported .



The detection of a port range or increment by the caller is made by
comparing  and . If both are equal, then port 0 means no port
was specified. The caller may pass NULL for  and  if it is not
interested in retrieving port ranges.



A prefix may be passed in before the address above to force the family :
- "ipv4@"  => force address to resolve as IPv4 and fail if not possible.
- "ipv6@"  => force address to resolve as IPv6 and fail if not possible.
- "unix@"  => force address to be a path to a UNIX socket even if the
path does not start with a '/'
- "fd@"    => an integer must follow, and is a file descriptor number.

Also note that in order to avoid any ambiguity with IPv6 addresses, the ':'
is mandatory after the IP address even when no port is specified. NULL is
returned if the address cannot be parsed. The  and  ports are
always initialized if non-null, even for non-IP families.

If  is non-null, it is used as a string prefix before any path-based
address (typically the path to a unix socket).

When a file descriptor is passed, its value is put into the s_addr part of
the address when cast to sockaddr_in and the address family is AF_UNSPEC.
Converts to a locally allocated struct sockaddr_storage * and a port range or offset consisting in two integers that the caller will have to check to find the relevant input format . The following format are supported . The detection of a port range or increment by the caller is made by comparing and . If both are equal then port 0 means no port was specified . The caller may pass NULL for and if it is not interested in retrieving port ranges . A prefix may be passed in before the address above to force the family : - " ipv4@ " = > force address to resolve as IPv4 and fail if not possible . - " ipv6@ " = > force address to resolve as IPv6 and fail if not possible . - " unix@ " = > force address to be a path to a UNIX socket even if the path does not start with a ' / ' - " fd@ " = > an integer must follow and is a file descriptor number . Also note that in order to avoid any ambiguity with IPv6 addresses the ' : ' is mandatory after the IP address even when no port is specified . NULL is returned if the address cannot be parsed . The and ports are always initialized if non - null even for non - IP families . If is non - null it is used as a string prefix before any path - based address ( typically the path to a unix socket ) . When a file descriptor is passed its value is put into the s_addr part of the address when cast to sockaddr_in and the address family is AF_UNSPEC .
struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, char **err, const char *pfx)
{
	static struct sockaddr_storage ss;
	struct sockaddr_storage *ret = NULL;
	char *back, *str2;
	char *port1, *port2;
	int portl, porth, porta;
	portl = porth = porta = 0;
	str2 = back = env_expand(strdup(str));
	if (str2 == NULL) {
		memprintf(err, "out of memory in '%s'\n", __FUNCTION__);
		goto out;
	}
	memset(&ss, 0, sizeof(ss));
	if (strncmp(str2, "unix@", 5) == 0) {
		str2 += 5;
		ss.ss_family = AF_UNIX;
	}
	else if (strncmp(str2, "ipv4@", 5) == 0) {
		str2 += 5;
		ss.ss_family = AF_INET;
	}
	else if (strncmp(str2, "ipv6@", 5) == 0) {
		str2 += 5;
		ss.ss_family = AF_INET6;
	}
	else if (*str2 == '/') {
		ss.ss_family = AF_UNIX;
	}
	else
		ss.ss_family = AF_UNSPEC;
	if (ss.ss_family == AF_UNSPEC && strncmp(str2, "fd@", 3) == 0) {
		char *endptr;
		str2 += 3;
		((struct sockaddr_in *)&ss)->sin_addr.s_addr = strtol(str2, &endptr, 10);
		if (!*str2 || *endptr) {
			memprintf(err, "file descriptor '%s' is not a valid integer in '%s'\n", str2, str);
			goto out;
		}
		ss.ss_family = AF_UNSPEC;
	}
	else if (ss.ss_family == AF_UNIX) {
		int prefix_path_len;
		int max_path_len;
		prefix_path_len = pfx ? strlen(pfx) : 0;
		max_path_len = (sizeof(((struct sockaddr_un *)&ss)->sun_path) - 1) -
			(prefix_path_len ? prefix_path_len + 1 + 5 + 1 + 3 : 0);
		if (strlen(str2) > max_path_len) {
			memprintf(err, "socket path '%s' too long (max %d)\n", str, max_path_len);
			goto out;
		}
		if (pfx) {
			memcpy(((struct sockaddr_un *)&ss)->sun_path, pfx, prefix_path_len);
			strcpy(((struct sockaddr_un *)&ss)->sun_path + prefix_path_len, str2);
		}
		else {
			strcpy(((struct sockaddr_un *)&ss)->sun_path, str2);
		}
	}
	else { 
		port1 = strrchr(str2, ':');
		if (port1)
			*port1++ = '\0';
		else
			port1 = "";
		if (str2ip(str2, &ss) == NULL) {
			memprintf(err, "invalid address: '%s' in '%s'\n", str2, str);
			goto out;
		}
		if (isdigit((int)(unsigned char)*port1)) {	
			port2 = strchr(port1, '-');
			if (port2)
				*port2++ = '\0';
			else
				port2 = port1;
			portl = atoi(port1);
			porth = atoi(port2);
			porta = portl;
		}
		else if (*port1 == '-') { 
			portl = atoi(port1 + 1);
			porta = -portl;
		}
		else if (*port1 == '+') { 
			porth = atoi(port1 + 1);
			porta = porth;
		}
		else if (*port1) { 
			memprintf(err, "invalid character '%c' in port number '%s' in '%s'\n", *port1, port1, str);
			goto out;
		}
		set_host_port(&ss, porta);
	}
	ret = &ss;
 out:
	if (low)
		*low = portl;
	if (high)
		*high = porth;
	free(back);
	return ret;
}
struct sockaddr_storage * str2sa_range ( const char * str , int * low , int * high , char * * err , const char * pfx ) { static struct sockaddr_storage ss ; struct sockaddr_storage * ret = NULL ; char * back , * str2 ; char * port1 , * port2 ; int portl , porth , porta ; portl = porth = porta = 0 ; str2 = back = env_expand ( strdup ( str ) ) ; if ( str2 == NULL ) { memprintf ( err , " \n " , __FUNCTION__ ) ; goto out ; } memset ( & ss , 0 , sizeof ( ss ) ) ; if ( strncmp ( str2 , " " , 5 ) == 0 ) { str2 += 5 ; ss . ss_family = AF_UNIX ; } else if ( strncmp ( str2 , " " , 5 ) == 0 ) { str2 += 5 ; ss . ss_family = AF_INET ; } else if ( strncmp ( str2 , " " , 5 ) == 0 ) { str2 += 5 ; ss . ss_family = AF_INET6 ; } else if ( * str2 == ' ' ) { ss . ss_family = AF_UNIX ; } else ss . ss_family = AF_UNSPEC ; if ( ss . ss_family == AF_UNSPEC && strncmp ( str2 , " " , 3 ) == 0 ) { char * endptr ; str2 += 3 ; ( ( struct sockaddr_in * ) & ss ) -> sin_addr . s_addr = strtol ( str2 , & endptr , 10 ) ; if ( ! * str2 || * endptr ) { memprintf ( err , " \n " , str2 , str ) ; goto out ; } ss . ss_family = AF_UNSPEC ; } else if ( ss . ss_family == AF_UNIX ) { int prefix_path_len ; int max_path_len ; prefix_path_len = pfx ? strlen ( pfx ) : 0 ; max_path_len = ( sizeof ( ( ( struct sockaddr_un * ) & ss ) -> sun_path ) - 1 ) - ( prefix_path_len ? prefix_path_len + 1 + 5 + 1 + 3 : 0 ) ; if ( strlen ( str2 ) > max_path_len ) { memprintf ( err , " \n " , str , max_path_len ) ; goto out ; } if ( pfx ) { memcpy ( ( ( struct sockaddr_un * ) & ss ) -> sun_path , pfx , prefix_path_len ) ; strcpy ( ( ( struct sockaddr_un * ) & ss ) -> sun_path + prefix_path_len , str2 ) ; } else { strcpy ( ( ( struct sockaddr_un * ) & ss ) -> sun_path , str2 ) ; } } else { port1 = strrchr ( str2 , ' ' ) ; if ( port1 ) * port1 ++ = ' \0 ' ; else port1 = " " ; if ( str2ip ( str2 , & ss ) == NULL ) { memprintf ( err , " \n " , str2 , str ) ; goto out ; } if ( isdigit ( ( int ) ( unsigned char ) * port1 ) ) { port2 = strchr ( port1 , ' ' ) ; if ( port2 ) * port2 ++ = ' \0 ' ; else port2 = port1 ; portl = atoi ( port1 ) ; porth = atoi ( port2 ) ; porta = portl ; } else if ( * port1 == ' ' ) { portl = atoi ( port1 + 1 ) ; porta = - portl ; } else if ( * port1 == ' ' ) { porth = atoi ( port1 + 1 ) ; porta = porth ; } else if ( * port1 ) { memprintf ( err , " \n " , * port1 , port1 , str ) ; goto out ; } set_host_port ( & ss , porta ) ; } ret = & ss ; out : if ( low ) * low = portl ; if ( high ) * high = porth ; free ( back ) ; return ret ; }
Converts <str> to a locally allocated struct sockaddr_storage *, and a port
 range or offset consisting in two integers that the caller will have to
 check to find the relevant input format.
Converts <str > to a locally allocated struct sockaddr_storage * and a port range or offset consisting in two integers that the caller will have to check to find the relevant input format .
/* we return AF_UNSPEC if we use a file descriptor number */ /* complete unix socket path name during startup or soft-restart is
		 * <unix_bind_prefix><path>.<pid>.<bak|tmp>
		 */ /* IPv4 and IPv6 */ /* single port or range */ /* negative offset */ /* positive offset */ /* other any unexpected char */