diff --git a/configure.in b/configure.in
index dfd26037be..748a6cdf82 100644
--- a/configure.in
+++ b/configure.in
@@ -297,12 +297,11 @@ dnl These headers are not essential
AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h syslog.h sys/time.h sys/resource.h pthread.h stddef.h inttypes.h)
-AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit setrlimit strlcat strlcpy strtoull getpwnam ftello pthread_create getaddrinfo localtime_r gmtime_r event_get_version event_get_method event_set_log_callback)
+AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit setrlimit strlcat strlcpy strtoull getpwnam ftello pthread_create getaddrinfo localtime_r gmtime_r event_get_version event_get_method event_set_log_callback memmem)
AC_FUNC_FSEEKO
AC_CHECK_MEMBERS([struct timeval.tv_sec])
-
dnl In case we aren't given a working stdint.h, we'll need to grow our own.
dnl Watch out.
diff --git a/src/common/compat.c b/src/common/compat.c
index 85db2b6ad4..f6fdda6e0a 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -13,7 +13,9 @@ const char compat_c_id[] = "$Id$";
* the platform.
**/
-/* This is required on rh7 to make strptime not complain. */
+/* This is required on rh7 to make strptime not complain.
+ * We also need it to make memmem get defined (where available)
+ */
#define _GNU_SOURCE
#include "orconfig.h"
@@ -134,6 +136,38 @@ tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
return r;
}
+/** Given hlen bytes at haystack and nlen bytes at
+ * needle, return a pointer to the first occurence of the needle
+ * within the haystack, or NULL if there is no such occurrence.
+ *
+ * Requires that nlen be greater than zero.
+ */
+const void *
+tor_memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen)
+{
+#if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2)
+ tor_assert(nlen);
+ return memmem(haystack, hlen, needle, nlen);
+#else
+ /* This isn't as fast as the GLIBC implementation, but it doesn't need to be. */
+ const void *p, *end;
+ char first;
+ tor_assert(nlen);
+
+ p = haystack;
+ end = haystack + hlen;
+ first = *(const char*)needle;
+ while ((p = memchr(p, first, end-p))) {
+ if (end-p >= nlen)
+ return NULL;
+ if (!memcmp(p, needle, nlen))
+ return p;
+ ++p;
+ }
+ return NULL;
+#endif
+}
+
/** Take a filename and return a pointer to its final element. This
* function is called on __FILE__ to fix a MSVC nit where __FILE__
* contains the full path to the file. This is bad, because it
diff --git a/src/common/compat.h b/src/common/compat.h
index 8f44e93857..dbf8828ab3 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -87,6 +87,9 @@ int tor_snprintf(char *str, size_t size, const char *format, ...)
CHECK_PRINTF(3,4);
int tor_vsnprintf(char *str, size_t size, const char *format, va_list args);
+const void *tor_memmem(const void *haystack, size_t hlen, const void *needle,
+ size_t nlen);
+
#define TOR_ISAPLHA(c) isalpha((int)(unsigned char)(c))
#define TOR_ISALNUM(c) isalnum((int)(unsigned char)(c))
#define TOR_ISSPACE(c) isspace((int)(unsigned char)(c))