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