1 /* $OpenBSD: evutil.c,v 1.2 2010/04/21 21:02:47 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Niels Provos <provos@citi.umich.edu> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 #ifdef HAVE_CONFIG_H 30 #include "config.h" 31 #endif 32 33 #ifdef WIN32 34 #include <winsock2.h> 35 #define WIN32_LEAN_AND_MEAN 36 #include <windows.h> 37 #undef WIN32_LEAN_AND_MEAN 38 #endif 39 40 #include <sys/types.h> 41 #ifdef HAVE_SYS_SOCKET_H 42 #include <sys/socket.h> 43 #endif 44 #ifdef HAVE_UNISTD_H 45 #include <unistd.h> 46 #endif 47 #ifdef HAVE_FCNTL_H 48 #include <fcntl.h> 49 #endif 50 #ifdef HAVE_STDLIB_H 51 #include <stdlib.h> 52 #endif 53 #include <errno.h> 54 #if defined WIN32 && !defined(HAVE_GETTIMEOFDAY_H) 55 #include <sys/timeb.h> 56 #endif 57 #include <stdio.h> 58 #include <signal.h> 59 60 #include <sys/queue.h> 61 #include "event.h" 62 #include "event-internal.h" 63 #include "evutil.h" 64 #include "log.h" 65 66 int 67 evutil_socketpair(int family, int type, int protocol, int fd[2]) 68 { 69 #ifndef WIN32 70 return socketpair(family, type, protocol, fd); 71 #else 72 /* This code is originally from Tor. Used with permission. */ 73 74 /* This socketpair does not work when localhost is down. So 75 * it's really not the same thing at all. But it's close enough 76 * for now, and really, when localhost is down sometimes, we 77 * have other problems too. 78 */ 79 int listener = -1; 80 int connector = -1; 81 int acceptor = -1; 82 struct sockaddr_in listen_addr; 83 struct sockaddr_in connect_addr; 84 int size; 85 int saved_errno = -1; 86 87 if (protocol 88 #ifdef AF_UNIX 89 || family != AF_UNIX 90 #endif 91 ) { 92 EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT); 93 return -1; 94 } 95 if (!fd) { 96 EVUTIL_SET_SOCKET_ERROR(WSAEINVAL); 97 return -1; 98 } 99 100 listener = socket(AF_INET, type, 0); 101 if (listener < 0) 102 return -1; 103 memset(&listen_addr, 0, sizeof(listen_addr)); 104 listen_addr.sin_family = AF_INET; 105 listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 106 listen_addr.sin_port = 0; /* kernel chooses port. */ 107 if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr)) 108 == -1) 109 goto tidy_up_and_fail; 110 if (listen(listener, 1) == -1) 111 goto tidy_up_and_fail; 112 113 connector = socket(AF_INET, type, 0); 114 if (connector < 0) 115 goto tidy_up_and_fail; 116 /* We want to find out the port number to connect to. */ 117 size = sizeof(connect_addr); 118 if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) 119 goto tidy_up_and_fail; 120 if (size != sizeof (connect_addr)) 121 goto abort_tidy_up_and_fail; 122 if (connect(connector, (struct sockaddr *) &connect_addr, 123 sizeof(connect_addr)) == -1) 124 goto tidy_up_and_fail; 125 126 size = sizeof(listen_addr); 127 acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size); 128 if (acceptor < 0) 129 goto tidy_up_and_fail; 130 if (size != sizeof(listen_addr)) 131 goto abort_tidy_up_and_fail; 132 EVUTIL_CLOSESOCKET(listener); 133 /* Now check we are talking to ourself by matching port and host on the 134 two sockets. */ 135 if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1) 136 goto tidy_up_and_fail; 137 if (size != sizeof (connect_addr) 138 || listen_addr.sin_family != connect_addr.sin_family 139 || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr 140 || listen_addr.sin_port != connect_addr.sin_port) 141 goto abort_tidy_up_and_fail; 142 fd[0] = connector; 143 fd[1] = acceptor; 144 145 return 0; 146 147 abort_tidy_up_and_fail: 148 saved_errno = WSAECONNABORTED; 149 tidy_up_and_fail: 150 if (saved_errno < 0) 151 saved_errno = WSAGetLastError(); 152 if (listener != -1) 153 EVUTIL_CLOSESOCKET(listener); 154 if (connector != -1) 155 EVUTIL_CLOSESOCKET(connector); 156 if (acceptor != -1) 157 EVUTIL_CLOSESOCKET(acceptor); 158 159 EVUTIL_SET_SOCKET_ERROR(saved_errno); 160 return -1; 161 #endif 162 } 163 164 int 165 evutil_make_socket_nonblocking(int fd) 166 { 167 #ifdef WIN32 168 { 169 unsigned long nonblocking = 1; 170 ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking); 171 } 172 #else 173 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 174 event_warn("fcntl(O_NONBLOCK)"); 175 return -1; 176 } 177 #endif 178 return 0; 179 } 180 181 ev_int64_t 182 evutil_strtoll(const char *s, char **endptr, int base) 183 { 184 #ifdef HAVE_STRTOLL 185 return (ev_int64_t)strtoll(s, endptr, base); 186 #elif SIZEOF_LONG == 8 187 return (ev_int64_t)strtol(s, endptr, base); 188 #elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300 189 /* XXXX on old versions of MS APIs, we only support base 190 * 10. */ 191 ev_int64_t r; 192 if (base != 10) 193 return 0; 194 r = (ev_int64_t) _atoi64(s); 195 while (isspace(*s)) 196 ++s; 197 while (isdigit(*s)) 198 ++s; 199 if (endptr) 200 *endptr = (char*) s; 201 return r; 202 #elif defined(WIN32) 203 return (ev_int64_t) _strtoi64(s, endptr, base); 204 #else 205 #error "I don't know how to parse 64-bit integers." 206 #endif 207 } 208 209 #ifndef HAVE_GETTIMEOFDAY 210 int 211 evutil_gettimeofday(struct timeval *tv, struct timezone *tz) 212 { 213 struct _timeb tb; 214 215 if(tv == NULL) 216 return -1; 217 218 _ftime(&tb); 219 tv->tv_sec = (long) tb.time; 220 tv->tv_usec = ((int) tb.millitm) * 1000; 221 return 0; 222 } 223 #endif 224 225 int 226 evutil_snprintf(char *buf, size_t buflen, const char *format, ...) 227 { 228 int r; 229 va_list ap; 230 va_start(ap, format); 231 r = evutil_vsnprintf(buf, buflen, format, ap); 232 va_end(ap); 233 return r; 234 } 235 236 int 237 evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap) 238 { 239 #ifdef _MSC_VER 240 int r = _vsnprintf(buf, buflen, format, ap); 241 buf[buflen-1] = '\0'; 242 if (r >= 0) 243 return r; 244 else 245 return _vscprintf(format, ap); 246 #else 247 int r = vsnprintf(buf, buflen, format, ap); 248 buf[buflen-1] = '\0'; 249 return r; 250 #endif 251 } 252 253 static int 254 evutil_issetugid(void) 255 { 256 #ifdef HAVE_ISSETUGID 257 return issetugid(); 258 #else 259 260 #ifdef HAVE_GETEUID 261 if (getuid() != geteuid()) 262 return 1; 263 #endif 264 #ifdef HAVE_GETEGID 265 if (getgid() != getegid()) 266 return 1; 267 #endif 268 return 0; 269 #endif 270 } 271 272 const char * 273 evutil_getenv(const char *varname) 274 { 275 if (evutil_issetugid()) 276 return NULL; 277 278 return getenv(varname); 279 } 280