+static inline unsigned port(const char *scheme)
+{
+ unsigned port = 80;
+
+#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R)
+ int rc;
+ size_t len = 0xff;
+ char *buf = NULL;
+ struct servent *se_res = NULL, se_buf = {0};
+
+ do {
+ buf = erealloc(buf, len);
+ rc = getservbyname_r(scheme, "tcp", &se_buf, buf, len, &se_res);
+ len *= 2;
+ } while (rc == ERANGE && len <= 0xfff);
+
+ if (!rc) {
+ port = ntohs(se_res->s_port);
+ }
+
+ efree(buf);
+#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT)
+ struct servent *se;
+
+ if ((se = getservbyname(scheme, "tcp")) && se->s_port) {
+ port = ntohs(se->s_port);
+ }
+#endif
+
+ return port;
+}
+static inline char *scheme(unsigned port)
+{
+ char *scheme;
+#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R)
+ int rc;
+ size_t len = 0xff;
+ char *buf = NULL;
+ struct servent *se_res = NULL, se_buf = {0};
+#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT)
+ struct servent *se;
+#endif
+
+ switch (port) {
+ case 443:
+ scheme = estrndup("https", lenof("https"));
+ break;
+
+#if defined(ZTS) && !defined(HAVE_GETSERVBYPORT_R)
+ default:
+#elif !defined(ZTS) && !defined(HAVE_GETSERVBYPORT)
+ default:
+#endif
+ case 80:
+ case 0:
+ scheme = estrndup("http", lenof("http"));
+ break;
+
+#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R)
+ default:
+ do {
+ buf = erealloc(buf, len);
+ rc = getservbyport_r(htons(port), "tcp", &se_buf, buf, len, &se_res);
+ len *= 2;
+ } while (rc == ERANGE && len <= 0xfff);
+
+ if (!rc && se_res) {
+ scheme = estrdup(se_res->s_name);
+ } else {
+ scheme = estrndup("http", lenof("http"));
+ }
+
+ efree(buf);
+ break;
+
+#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT)
+ default:
+ if ((se = getservbyport(htons(port), "tcp")) && se->s_name) {
+ scheme = estrdup(se->s_name);
+ } else {
+ scheme = estrndup("http", lenof("http"));
+ }
+ break;
+#endif
+ }
+ return scheme;
+}
+