Fix return value of writeHeaders.
[polipo.git] / util.c
blobce7ef74002e40297789ed0a3a75efea72d1aa2b3
1 /*
2 Copyright (c) 2003-2007 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
23 #include "polipo.h"
25 /* Note that this is different from GNU's strndup(3). */
26 char *
27 strdup_n(const char *restrict buf, int n)
29 char *s;
30 s = malloc(n + 1);
31 if(s == NULL)
32 return NULL;
33 memcpy(s, buf, n);
34 s[n] = '\0';
35 return s;
38 int
39 snnprintf(char *restrict buf, int n, int len, const char *format, ...)
41 va_list args;
42 int rc;
43 va_start(args, format);
44 rc = snnvprintf(buf, n, len, format, args);
45 va_end(args);
46 return rc;
49 int
50 snnvprintf(char *restrict buf, int n, int len, const char *format, va_list args)
52 int rc = -1;
53 if(n < 0) return -2;
54 if(n < len)
55 rc = vsnprintf(buf + n, len - n, format, args);
56 if(rc >= 0 && n + rc <= len)
57 return n + rc;
58 else
59 return -1;
62 int
63 snnprint_n(char *restrict buf, int n, int len, const char *s, int slen)
65 int i = 0;
66 if(n < 0) return -2;
67 while(i < slen && n < len)
68 buf[n++] = s[i++];
69 if(n < len)
70 return n;
71 else
72 return -1;
75 int
76 strcmp_n(const char *string, const char *buf, int n)
78 int i;
79 i = 0;
80 while(string[i] != '\0' && i < n) {
81 if(string[i] < buf[i])
82 return -1;
83 else if(string[i] > buf[i])
84 return 1;
85 i++;
87 if(string[i] == '\0' || i == n)
88 return 0;
89 else if(i == n)
90 return 1;
91 else
92 return -1;
95 int
96 letter(char c)
98 if(c >= 'A' && c <= 'Z') return 1;
99 if(c >= 'a' && c <= 'z') return 1;
100 return 0;
104 digit(char c)
106 if(c >= '0' && c <= '9')
107 return 1;
108 return 0;
111 char
112 lwr(char a)
114 if(a >= 'A' && a <= 'Z')
115 return a | 0x20;
116 else
117 return a;
120 char *
121 lwrcpy(char *restrict dst, const char *restrict src, int n)
123 int i;
124 for(i = 0; i < n; i++)
125 dst[i] = lwr(src[i]);
126 return dst;
130 lwrcmp(const char *as, const char *bs, int n)
132 int i;
133 for(i = 0; i < n; i++) {
134 char a = lwr(as[i]), b = lwr(bs[i]);
135 if(a < b)
136 return -1;
137 else if(a > b)
138 return 1;
140 return 0;
144 strcasecmp_n(const char *string, const char *buf, int n)
146 int i;
147 i = 0;
148 while(string[i] != '\0' && i < n) {
149 char a = lwr(string[i]), b = lwr(buf[i]);
150 if(a < b)
151 return -1;
152 else if(a > b)
153 return 1;
154 i++;
156 if(string[i] == '\0' && i == n)
157 return 0;
158 else if(i == n)
159 return 1;
160 else
161 return -1;
165 atoi_n(const char *restrict string, int n, int len, int *value_return)
167 int i = n;
168 int val = 0;
170 if(i >= len || !digit(string[i]))
171 return -1;
173 while(i < len && digit(string[i])) {
174 val = val * 10 + (string[i] - '0');
175 i++;
177 *value_return = val;
178 return i;
181 int
182 isWhitespace(const char *string)
184 while(*string != '\0') {
185 if(*string == ' ' || *string == '\t')
186 string++;
187 else
188 return 0;
190 return 1;
193 #ifndef HAVE_MEMRCHR
194 void *
195 memrchr(const void *s, int c, size_t n)
197 const unsigned char *ss = s;
198 unsigned char cc = c;
199 size_t i;
200 for(i = n - 1; i >= 0; i--)
201 if(ss[i] == cc)
202 return (void*)(ss + i);
203 return NULL;
205 #endif
208 h2i(char h)
210 if(h >= '0' && h <= '9')
211 return h - '0';
212 else if(h >= 'a' && h <= 'f')
213 return h - 'a' + 10;
214 else if(h >= 'A' && h <= 'F')
215 return h - 'A' + 10;
216 else
217 return -1;
220 char
221 i2h(int i)
223 if(i < 0 || i >= 16)
224 return '?';
225 if(i < 10)
226 return i + '0';
227 else
228 return i - 10 + 'A';
231 /* floor(log2(x)) */
233 log2_floor(int x)
235 int i, j;
237 assert(x > 0);
239 i = 0;
240 j = 1;
241 while(2 * j <= x) {
242 i++;
243 j *= 2;
245 return i;
248 /* ceil(log2(x)) */
250 log2_ceil(int x)
252 int i, j;
254 assert(x > 0);
256 i = 0;
257 j = 1;
258 while(j < x) {
259 i++;
260 j *= 2;
262 return i;
265 #ifdef HAVE_ASPRINTF
266 char *
267 vsprintf_a(const char *f, va_list args)
269 char *r;
270 int rc;
272 rc = vasprintf(&r, f, args);
273 if(rc < 0)
274 return NULL;
275 return r;
279 #else
281 /* This is not going to work if va_list is interesting. But then, if you
282 have a non-trivial implementation of va_list, you should have va_copy. */
283 #ifndef va_copy
284 #define va_copy(a, b) do { a = b; } while(0)
285 #endif
287 char*
288 vsprintf_a(const char *f, va_list args)
290 int n, size;
291 char buf[64];
292 char *string;
293 va_list args_copy;
295 va_copy(args_copy, args);
296 n = vsnprintf(buf, 64, f, args_copy);
297 if(n >= 0 && n < 64) {
298 return strdup_n(buf, n);
300 if(n >= 64)
301 size = n + 1;
302 else
303 size = 96;
305 while(1) {
306 string = malloc(size);
307 if(!string)
308 return NULL;
309 va_copy(args_copy, args);
310 n = vsnprintf(string, size, f, args_copy);
311 if(n >= 0 && n < size)
312 return string;
313 else if(n >= size)
314 size = n + 1;
315 else
316 size = size * 3 / 2;
317 free(string);
318 if(size > 16 * 1024)
319 return NULL;
321 /* NOTREACHED */
323 #endif
325 char*
326 sprintf_a(const char *f, ...)
328 char *s;
329 va_list args;
330 va_start(args, f);
331 s = vsprintf_a(f, args);
332 va_end(args);
333 return s;
336 unsigned int
337 hash(unsigned int seed, const void *restrict key, int key_size,
338 unsigned int hash_size)
340 int i;
341 unsigned int h;
343 h = seed;
344 for(i = 0; i < key_size; i++)
345 h = (h << 5) + (h >> (hash_size - 5)) +
346 ((unsigned char*)key)[i];
347 return h & ((1 << hash_size) - 1);
350 char *
351 pstrerror(int e)
353 char *s;
354 static char buf[20];
356 switch(e) {
357 case EDOSHUTDOWN: s = "Immediate shutdown requested"; break;
358 case EDOGRACEFUL: s = "Graceful shutdown requested"; break;
359 case EDOTIMEOUT: s = "Timeout"; break;
360 case ECLIENTRESET: s = "Connection reset by client"; break;
361 case ESYNTAX: s = "Incorrect syntax"; break;
362 case EREDIRECTOR: s = "Redirector error"; break;
363 case EDNS_HOST_NOT_FOUND: s = "Host not found"; break;
364 case EDNS_NO_ADDRESS: s = "No address"; break;
365 case EDNS_NO_RECOVERY: s = "Permanent name server failure"; break;
366 case EDNS_TRY_AGAIN: s = "Temporary name server failure"; break;
367 case EDNS_INVALID: s = "Invalid reply from name server"; break;
368 case EDNS_UNSUPPORTED: s = "Unsupported DNS reply"; break;
369 case EDNS_FORMAT: s = "Invalid DNS query"; break;
370 case EDNS_REFUSED: s = "DNS query refused by server"; break;
371 case EDNS_CNAME_LOOP: s = "DNS CNAME loop"; break;
372 #ifndef NO_SOCKS
373 case ESOCKS_PROTOCOL: s = "SOCKS protocol error"; break;
374 case ESOCKS_REJECT_FAIL: s = "SOCKS request rejected or failed"; break;
375 case ESOCKS_REJECT_IDENTD: s = "SOCKS request rejected: "
376 "server couldn't connect to identd";
377 case ESOCKS_REJECT_UID_MISMATCH: s = "SOCKS request rejected: "
378 "uid mismatch";
379 break;
380 case ESOCKS5_BASE: s = "SOCKS success"; break;
381 case ESOCKS5_BASE + 1: s = "General SOCKS server failure"; break;
382 case ESOCKS5_BASE + 2: s = "SOCKS connection not allowed"; break;
383 case ESOCKS5_BASE + 3: s = "SOCKS error: network unreachable"; break;
384 case ESOCKS5_BASE + 4: s = "SOCKS error: host unreachable"; break;
385 case ESOCKS5_BASE + 5: s = "SOCKS error: connection refused"; break;
386 case ESOCKS5_BASE + 6: s = "SOCKS error: TTL expired"; break;
387 case ESOCKS5_BASE + 7: s = "SOCKS command not supported"; break;
388 case ESOCKS5_BASE + 8: s = "SOCKS error: address type not supported";
389 break;
390 #endif
391 case EUNKNOWN: s = "Unknown error"; break;
392 default: s = NULL; break;
394 if(!s) s = strerror(e);
395 #ifdef MINGW
396 if(!s) {
397 if(e >= WSABASEERR && e <= WSABASEERR + 2000) {
398 /* This should be okay, as long as the caller discards the
399 pointer before another error occurs. */
400 snprintf(buf, 20, "Winsock error %d", e);
401 s = buf;
404 #endif
405 if(!s) {
406 snprintf(buf, 20, "Unknown error %d", e);
407 s = buf;
409 return s;
412 /* Like mktime(3), but UTC rather than local time */
413 #if defined(HAVE_TIMEGM)
414 time_t
415 mktime_gmt(struct tm *tm)
417 return timegm(tm);
419 #elif defined(HAVE_TM_GMTOFF)
420 time_t
421 mktime_gmt(struct tm *tm)
423 time_t t;
424 struct tm *ltm;
426 t = mktime(tm);
427 if(t < 0)
428 return -1;
429 ltm = localtime(&t);
430 if(ltm == NULL)
431 return -1;
432 return t + ltm->tm_gmtoff;
434 #elif defined(HAVE_TZSET)
435 #ifdef HAVE_SETENV
436 /* Taken from the Linux timegm(3) man page. */
437 time_t
438 mktime_gmt(struct tm *tm)
440 time_t t;
441 char *tz;
443 tz = getenv("TZ");
444 setenv("TZ", "", 1);
445 tzset();
446 t = mktime(tm);
447 if(tz)
448 setenv("TZ", tz, 1);
449 else
450 unsetenv("TZ");
451 tzset();
452 return t;
454 #else
455 time_t
456 mktime_gmt(struct tm *tm)
458 time_t t;
459 char *tz;
460 static char *old_tz = NULL;
462 tz = getenv("TZ");
463 putenv("TZ=");
464 tzset();
465 t = mktime(tm);
466 if(old_tz)
467 free(old_tz);
468 if(tz)
469 old_tz = sprintf_a("TZ=%s", tz);
470 else
471 old_tz = strdup("TZ"); /* XXX - non-portable? */
472 if(old_tz)
473 putenv(old_tz);
474 tzset();
475 return t;
477 #endif
478 #else
479 #error no mktime_gmt implementation on this platform
480 #endif
483 AtomPtr
484 expandTilde(AtomPtr filename)
486 char *buf;
487 char *home;
488 int len;
489 AtomPtr ret;
491 if(filename == NULL || filename->length < 1 ||
492 filename->string[0] != '~' || filename->string[1] != '/')
493 return filename;
495 home = getenv("HOME");
496 if(home == NULL) {
497 return NULL;
499 len = strlen(home);
500 buf = malloc(len + 1 + 1 + filename->length - 2);
501 if(buf == NULL) {
502 do_log(L_ERROR, "Could not allocate buffer.\n");
503 return NULL;
506 memcpy(buf, home, len);
507 if(buf[len - 1] != '/')
508 buf[len++] = '/';
509 memcpy(buf + len, filename->string + 2, filename->length - 2);
510 len += filename->length - 2;
511 ret = internAtomN(buf, len);
512 free(buf);
513 if(ret != NULL)
514 releaseAtom(filename);
515 return ret;
518 #ifdef HAVE_FORK
519 void
520 do_daemonise(int noclose)
522 int rc;
524 fflush(stdout);
525 fflush(stderr);
527 rc = fork();
528 if(rc < 0) {
529 do_log_error(L_ERROR, errno, "Couldn't fork");
530 exit(1);
533 if(rc > 0)
534 exit(0);
536 if(!noclose) {
537 close(0);
538 close(1);
539 close(2);
541 rc = setsid();
542 if(rc < 0) {
543 do_log_error(L_ERROR, errno, "Couldn't create new session");
544 exit(1);
548 #else
550 void
551 do_daemonise(int noclose)
553 do_log(L_ERROR, "Cannot daemonise on this platform");
554 exit(1);
556 #endif
559 void
560 writePid(char *pidfile)
562 int fd, n, rc;
563 char buf[16];
565 fd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
566 if(fd < 0) {
567 do_log_error(L_ERROR, errno,
568 "Couldn't create pid file %s", pidfile);
569 exit(1);
571 n = snprintf(buf, 16, "%ld\n", (long)getpid());
572 if(n < 0 || n >= 16) {
573 close(fd);
574 unlink(pidfile);
575 do_log(L_ERROR, "Couldn't format pid.\n");
576 exit(1);
578 rc = write(fd, buf, n);
579 if(rc != n) {
580 close(fd);
581 unlink(pidfile);
582 do_log_error(L_ERROR, errno, "Couldn't write pid");
583 exit(1);
586 close(fd);
587 return;
590 static const char b64[64] =
591 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
593 /* "/" replaced with "-" */
594 static const char b64fss[64] =
595 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
598 b64cpy(char *restrict dst, const char *restrict src, int n, int fss)
600 const char *b = fss ? b64fss: b64;
601 int i, j;
603 j = 0;
604 for(i = 0; i < n; i += 3) {
605 unsigned char a0, a1, a2;
606 a0 = src[i];
607 a1 = i < n - 1 ? src[i + 1] : 0;
608 a2 = i < n - 2 ? src[i + 2] : 0;
609 dst[j++] = b[(a0 >> 2) & 0x3F];
610 dst[j++] = b[((a0 << 4) & 0x30) | ((a1 >> 4) & 0x0F)];
611 if(i < n - 1)
612 dst[j++] = b[((a1 << 2) & 0x3C) | ((a2 >> 6) & 0x03)];
613 else
614 dst[j++] = '=';
615 if(i < n - 2)
616 dst[j++] = b[a2 & 0x3F];
617 else
618 dst[j++] = '=';
620 return j;
624 b64cmp(const char *restrict a, int an, const char *restrict b, int bn)
626 char *buf;
627 int r;
629 if(an % 4 != 0)
630 return -1;
631 if((bn + 2) / 3 != an / 4)
632 return -1;
633 buf = malloc(an);
634 if(buf == NULL)
635 return -1;
636 b64cpy(buf, b, bn, 0);
637 r = memcmp(buf, a, an);
638 free(buf);
639 return r;
642 IntListPtr
643 makeIntList(int size)
645 IntListPtr list;
646 if(size <= 0)
647 size = 4;
649 list = malloc(sizeof(IntListRec));
650 if(list == NULL)
651 return NULL;
653 list->ranges = malloc(size * sizeof(IntRangeRec));
654 if(list->ranges == NULL) {
655 free(list);
656 return NULL;
659 list->length = 0;
660 list->size = size;
661 return list;
664 void
665 destroyIntList(IntListPtr list)
667 free(list->ranges);
668 free(list);
672 intListMember(int n, IntListPtr list)
674 int lo = 0, hi = list->length - 1;
675 int mid;
676 while(hi >= lo) {
677 mid = (hi + lo) / 2;
678 if(list->ranges[mid].from > n)
679 hi = mid - 1;
680 else if(list->ranges[mid].to < n)
681 lo = mid + 1;
682 else
683 return 1;
685 return 0;
688 static int
689 deleteRange(IntListPtr list, int i)
691 assert(list->length > i);
692 if(list->length > i + 1)
693 memmove(list->ranges + i, list->ranges + i + 1,
694 (list->length - i - 1) * sizeof(IntRangeRec));
695 list->length--;
696 return 1;
699 static int
700 insertRange(int from, int to, IntListPtr list, int i)
702 assert(i >= 0 && i <= list->length);
703 assert(i == 0 || list->ranges[i - 1].to < from - 1);
704 assert(i == list->length || list->ranges[i].from > to + 1);
706 if(list->length >= list->size) {
707 int newsize = list->size * 2 + 1;
708 IntRangePtr newranges =
709 realloc(list->ranges, newsize * sizeof(IntRangeRec));
710 if(newranges == NULL)
711 return -1;
712 list->size = newsize;
713 list->ranges = newranges;
716 if(i < list->length)
717 memmove(list->ranges + i + 1, list->ranges + i,
718 list->length - i);
719 list->length++;
720 list->ranges[i].from = from;
721 list->ranges[i].to = to;
722 return 1;
725 static int
726 maybeMergeRanges(IntListPtr list, int i)
728 int rc;
730 while(i > 0 && list->ranges[i].from <= list->ranges[i - 1].to + 1) {
731 list->ranges[i - 1].from =
732 MIN(list->ranges[i - 1].from, list->ranges[i].from);
733 list->ranges[i - 1].to =
734 MAX(list->ranges[i - 1].to, list->ranges[i].to);
735 rc = deleteRange(list, i);
736 if(rc < 0) return -1;
737 i--;
740 while(i < list->length - 1 &&
741 list->ranges[i].to >= list->ranges[i + 1].from - 1) {
742 list->ranges[i + 1].from =
743 MIN(list->ranges[i + 1].from, list->ranges[i].from);
744 list->ranges[i - 1].to =
745 MAX(list->ranges[i + 1].to, list->ranges[i].to);
746 rc = deleteRange(list, i);
747 if(rc < 0) return -1;
749 return 1;
753 intListCons(int from, int to, IntListPtr list)
755 int i;
757 /* Don't bother with the dichotomy. */
758 for(i = 0; i < list->length; i++) {
759 if(list->ranges[i].to >= from - 1)
760 break;
763 if(i < list->length &&
764 (from >= list->ranges[i].from - 1 || to <= list->ranges[i].to + 1)) {
765 if(from <= list->ranges[i].from)
766 list->ranges[i].from = from;
767 if(to >= list->ranges[i].to)
768 list->ranges[i].to = to;
769 return maybeMergeRanges(list, i);
771 return insertRange(from, to, list, i);
774 /* Return the amount of physical memory on the box, -1 if unknown or
775 over two gigs. */
776 #if defined(__linux__)
778 #include <sys/sysinfo.h>
780 physicalMemory()
782 int rc;
783 struct sysinfo info;
785 rc = sysinfo(&info);
786 if(rc < 0)
787 return -1;
789 if(info.totalram <= 0x7fffffff / info.mem_unit)
790 return (int)(info.totalram * info.mem_unit);
792 return -1;
795 #elif defined(__FreeBSD__)
797 #include <sys/sysctl.h>
799 physicalMemory()
801 int membytes;
802 size_t len;
803 int res;
805 len = sizeof(membytes);
806 res = sysctlbyname("hw.physmem", &membytes, &len, NULL, 0);
807 if (res)
808 return -1;
810 return membytes;
813 #else
816 physicalMemory()
818 return -1;
820 #endif