MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
evutil.c
1 /*
2  * Copyright (c) 2007 Niels Provos <provos@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 
57 #include "evutil.h"
58 #include "log.h"
59 
60 int
61 evutil_socketpair(int family, int type, int protocol, int fd[2])
62 {
63 #ifndef WIN32
64  return socketpair(family, type, protocol, fd);
65 #else
66  /* This code is originally from Tor. Used with permission. */
67 
68  /* This socketpair does not work when localhost is down. So
69  * it's really not the same thing at all. But it's close enough
70  * for now, and really, when localhost is down sometimes, we
71  * have other problems too.
72  */
73  int listener = -1;
74  int connector = -1;
75  int acceptor = -1;
76  struct sockaddr_in listen_addr;
77  struct sockaddr_in connect_addr;
78  int size;
79  int saved_errno = -1;
80 
81  if (protocol
82 #ifdef AF_UNIX
83  || family != AF_UNIX
84 #endif
85  ) {
86  EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT);
87  return -1;
88  }
89  if (!fd) {
90  EVUTIL_SET_SOCKET_ERROR(WSAEINVAL);
91  return -1;
92  }
93 
94  listener = socket(AF_INET, type, 0);
95  if (listener < 0)
96  return -1;
97  memset(&listen_addr, 0, sizeof(listen_addr));
98  listen_addr.sin_family = AF_INET;
99  listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
100  listen_addr.sin_port = 0; /* kernel chooses port. */
101  if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
102  == -1)
103  goto tidy_up_and_fail;
104  if (listen(listener, 1) == -1)
105  goto tidy_up_and_fail;
106 
107  connector = socket(AF_INET, type, 0);
108  if (connector < 0)
109  goto tidy_up_and_fail;
110  /* We want to find out the port number to connect to. */
111  size = sizeof(connect_addr);
112  if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
113  goto tidy_up_and_fail;
114  if (size != sizeof (connect_addr))
115  goto abort_tidy_up_and_fail;
116  if (connect(connector, (struct sockaddr *) &connect_addr,
117  sizeof(connect_addr)) == -1)
118  goto tidy_up_and_fail;
119 
120  size = sizeof(listen_addr);
121  acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
122  if (acceptor < 0)
123  goto tidy_up_and_fail;
124  if (size != sizeof(listen_addr))
125  goto abort_tidy_up_and_fail;
126  EVUTIL_CLOSESOCKET(listener);
127  /* Now check we are talking to ourself by matching port and host on the
128  two sockets. */
129  if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
130  goto tidy_up_and_fail;
131  if (size != sizeof (connect_addr)
132  || listen_addr.sin_family != connect_addr.sin_family
133  || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
134  || listen_addr.sin_port != connect_addr.sin_port)
135  goto abort_tidy_up_and_fail;
136  fd[0] = connector;
137  fd[1] = acceptor;
138 
139  return 0;
140 
141  abort_tidy_up_and_fail:
142  saved_errno = WSAECONNABORTED;
143  tidy_up_and_fail:
144  if (saved_errno < 0)
145  saved_errno = WSAGetLastError();
146  if (listener != -1)
147  EVUTIL_CLOSESOCKET(listener);
148  if (connector != -1)
149  EVUTIL_CLOSESOCKET(connector);
150  if (acceptor != -1)
151  EVUTIL_CLOSESOCKET(acceptor);
152 
153  EVUTIL_SET_SOCKET_ERROR(saved_errno);
154  return -1;
155 #endif
156 }
157 
158 int
159 evutil_make_socket_nonblocking(int fd)
160 {
161 #ifdef WIN32
162  {
163  unsigned long nonblocking = 1;
164  ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
165  }
166 #else
167  if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
168  event_warn("fcntl(O_NONBLOCK)");
169  return -1;
170 }
171 #endif
172  return 0;
173 }
174 
175 ev_int64_t
176 evutil_strtoll(const char *s, char **endptr, int base)
177 {
178 #ifdef HAVE_STRTOLL
179  return (ev_int64_t)strtoll(s, endptr, base);
180 #elif SIZEOF_LONG == 8
181  return (ev_int64_t)strtol(s, endptr, base);
182 #elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
183  /* XXXX on old versions of MS APIs, we only support base
184  * 10. */
185  ev_int64_t r;
186  if (base != 10)
187  return 0;
188  r = (ev_int64_t) _atoi64(s);
189  while (isspace(*s))
190  ++s;
191  while (isdigit(*s))
192  ++s;
193  if (endptr)
194  *endptr = (char*) s;
195  return r;
196 #elif defined(WIN32)
197  return (ev_int64_t) _strtoi64(s, endptr, base);
198 #else
199 #error "I don't know how to parse 64-bit integers."
200 #endif
201 }
202 
203 #ifndef HAVE_GETTIMEOFDAY
204 int
205 evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
206 {
207  struct _timeb tb;
208 
209  if(tv == NULL)
210  return -1;
211 
212  _ftime(&tb);
213  tv->tv_sec = (long) tb.time;
214  tv->tv_usec = ((int) tb.millitm) * 1000;
215  return 0;
216 }
217 #endif
218 
219 int
220 evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
221 {
222  int r;
223  va_list ap;
224  va_start(ap, format);
225  r = evutil_vsnprintf(buf, buflen, format, ap);
226  va_end(ap);
227  return r;
228 }
229 
230 int
231 evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
232 {
233 #ifdef _MSC_VER
234  int r = _vsnprintf(buf, buflen, format, ap);
235  buf[buflen-1] = '\0';
236  if (r >= 0)
237  return r;
238  else
239  return _vscprintf(format, ap);
240 #else
241  int r = vsnprintf(buf, buflen, format, ap);
242  buf[buflen-1] = '\0';
243  return r;
244 #endif
245 }