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