mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Attempt to make sockets code work right on windows.
svn:r398
This commit is contained in:
+19
-4
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "fakepoll.h"
|
||||
|
||||
#ifdef USE_FAKE_POLL
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
@@ -30,6 +31,9 @@ poll(struct pollfd *ufds, unsigned int nfds, int timeout)
|
||||
{
|
||||
unsigned int idx, maxfd, fd;
|
||||
int r;
|
||||
#ifdef MS_WINDOWS
|
||||
int any_fds_set = 0;
|
||||
#endif
|
||||
fd_set readfds, writefds, exceptfds;
|
||||
#ifdef USING_FAKE_TIMEVAL
|
||||
#undef timeval
|
||||
@@ -46,15 +50,26 @@ poll(struct pollfd *ufds, unsigned int nfds, int timeout)
|
||||
maxfd = -1;
|
||||
for (idx = 0; idx < nfds; ++idx) {
|
||||
fd = ufds[idx].fd;
|
||||
if (fd > maxfd && ufds[idx].events)
|
||||
maxfd = fd;
|
||||
if (ufds[idx].events & (POLLIN))
|
||||
if (ufds[idx].events) {
|
||||
if (fd > maxfd)
|
||||
maxfd = fd;
|
||||
#ifdef MS_WINDOWS
|
||||
any_fds_set = 1;
|
||||
#endif
|
||||
}
|
||||
if (ufds[idx].events & POLLIN)
|
||||
FD_SET(fd, &readfds);
|
||||
if (ufds[idx].events & POLLOUT)
|
||||
FD_SET(fd, &writefds);
|
||||
if (ufds[idx].events & (POLLERR))
|
||||
if (ufds[idx].events & POLLERR)
|
||||
FD_SET(fd, &exceptfds);
|
||||
}
|
||||
#ifdef MS_WINDOWS
|
||||
if (!any_fds_set) {
|
||||
usleep(timeout);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
r = select(maxfd+1, &readfds, &writefds, &exceptfds,
|
||||
timeout == -1 ? NULL : &_timeout);
|
||||
if (r <= 0)
|
||||
|
||||
+21
-8
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "../or/or.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MS_WINDOWS
|
||||
#include <io.h>
|
||||
#include <limits.h>
|
||||
#include <process.h>
|
||||
@@ -90,7 +90,7 @@ void tv_addms(struct timeval *a, long ms) {
|
||||
|
||||
void set_socket_nonblocking(int socket)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MS_WINDOWS
|
||||
/* Yes means no and no means yes. Do you not want to be nonblocking? */
|
||||
int nonblocking = 0;
|
||||
ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
|
||||
@@ -101,7 +101,7 @@ void set_socket_nonblocking(int socket)
|
||||
|
||||
int spawn_func(int (*func)(void *), void *data)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MS_WINDOWS
|
||||
int rv;
|
||||
rv = _beginthread(func, 0, data);
|
||||
if (rv == (unsigned long) -1)
|
||||
@@ -125,7 +125,7 @@ int spawn_func(int (*func)(void *), void *data)
|
||||
|
||||
void spawn_exit()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MS_WINDOWS
|
||||
_endthread();
|
||||
#else
|
||||
exit(0);
|
||||
@@ -137,7 +137,7 @@ void spawn_exit()
|
||||
int
|
||||
tor_socketpair(int family, int type, int protocol, int fd[2])
|
||||
{
|
||||
#ifdef HAVE_SOCKETPAIR_XXX
|
||||
#ifdef HAVE_SOCKETPAIR_XXXX
|
||||
/* For testing purposes, we never fall back to real socketpairs. */
|
||||
return socketpair(family, type, protocol, fd);
|
||||
#else
|
||||
@@ -153,8 +153,8 @@ tor_socketpair(int family, int type, int protocol, int fd[2])
|
||||
|| family != AF_UNIX
|
||||
#endif
|
||||
) {
|
||||
#ifdef _MSC_VER
|
||||
errno = WSAEAFNOSUPPORT;
|
||||
#ifdef MS_WINDOWS
|
||||
errno = WSAEAFNOSUPPORT;
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
#endif
|
||||
@@ -213,7 +213,7 @@ tor_socketpair(int family, int type, int protocol, int fd[2])
|
||||
return 0;
|
||||
|
||||
abort_tidy_up_and_fail:
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MS_WINDOWS
|
||||
errno = WSAECONNABORTED;
|
||||
#else
|
||||
errno = ECONNABORTED; /* I hope this is portable and appropriate. */
|
||||
@@ -232,3 +232,16 @@ tor_socketpair(int family, int type, int protocol, int fd[2])
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
int correct_socket_errno(int s)
|
||||
{
|
||||
int r, optval, optvallen=sizeof(optval);
|
||||
assert(errno == WSAEWOULDBLOCK);
|
||||
if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen))
|
||||
return errno;
|
||||
if (optval)
|
||||
return optval;
|
||||
return WSAEWOULDBLOCK;
|
||||
}
|
||||
#endif
|
||||
|
||||
+27
-1
@@ -13,6 +13,12 @@
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#if _MSC_VER > 1300
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
#ifdef HAVE_FTIME
|
||||
#define USING_FAKE_TIMEVAL
|
||||
@@ -23,7 +29,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MS_WINDOWS
|
||||
/* Windows names string functions funnily. */
|
||||
#define strncasecmp strnicmp
|
||||
#define strcasecmp stricmp
|
||||
@@ -55,4 +61,24 @@ void spawn_exit();
|
||||
|
||||
int tor_socketpair(int family, int type, int protocol, int fd[2]);
|
||||
|
||||
/* For stupid historical reasons, windows sockets have an independent set of
|
||||
* errnos which they use as the fancy strikes them.
|
||||
*/
|
||||
#ifdef MS_WINDOWS
|
||||
#define ERRNO_EAGAIN(e) ((e) == EAGAIN || \
|
||||
(e) == WSAEWOULDBLOCK || \
|
||||
(e) == EWOULDBLOCK)
|
||||
#define ERRNO_EINPROGRESS(e) ((e) == EINPROGRESS || \
|
||||
(e) == WSAEINPROGRESS)
|
||||
#define ERRNO_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || \
|
||||
(e) == WSAEINPROGRESS || (e) == WSAEINVAL)
|
||||
int correct_socket_errno(int s);
|
||||
#else
|
||||
#define ERRNO_EAGAIN(e) ((e) == EAGAIN)
|
||||
#define ERRNO_EINPROGRESS(e) ((e) == EINPROGRESS)
|
||||
#define ERRNO_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
|
||||
#define correct_socket_errno(s) (errno)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+20
-2
@@ -36,6 +36,9 @@ void buf_free(char *buf) {
|
||||
int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof) {
|
||||
|
||||
int read_result;
|
||||
#ifdef MS_WINDOWS
|
||||
int e;
|
||||
#endif
|
||||
|
||||
assert(buf && *buf && buflen && buf_datalen && reached_eof && (s>=0));
|
||||
|
||||
@@ -62,9 +65,15 @@ int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, i
|
||||
// log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most);
|
||||
read_result = read(s, *buf+*buf_datalen, at_most);
|
||||
if (read_result < 0) {
|
||||
if(errno!=EAGAIN) { /* it's a real error */
|
||||
if(!ERRNO_EAGAIN(errno)) { /* it's a real error */
|
||||
return -1;
|
||||
}
|
||||
#ifdef MS_WINDOWS
|
||||
e = correct_socket_errno(s);
|
||||
if(!ERRNO_EAGAIN(errno)) { /* no, it *is* a real error! */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
} else if (read_result == 0) {
|
||||
log_fn(LOG_DEBUG,"Encountered eof");
|
||||
@@ -84,6 +93,9 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale
|
||||
* return -1 or how many bytes remain to be flushed */
|
||||
|
||||
int write_result;
|
||||
#ifdef MS_WINDOWS
|
||||
int e;
|
||||
#endif
|
||||
|
||||
assert(buf && *buf && buflen && buf_flushlen && buf_datalen && (s>=0) && (*buf_flushlen <= *buf_datalen));
|
||||
|
||||
@@ -94,9 +106,15 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale
|
||||
|
||||
write_result = write(s, *buf, *buf_flushlen);
|
||||
if (write_result < 0) {
|
||||
if(errno!=EAGAIN) { /* it's a real error */
|
||||
if(!ERRNO_EAGAIN(errno)) { /* it's a real error */
|
||||
return -1;
|
||||
}
|
||||
#ifdef MS_WINDOWS
|
||||
e = correct_socket_errno(s);
|
||||
if(!ERRNO_EAGAIN(errno)) { /* no, it *is* a real error! */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
log_fn(LOG_DEBUG,"write() would block, returning.");
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
+11
-1
@@ -188,11 +188,21 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st
|
||||
connection_t *newconn;
|
||||
struct sockaddr_in remote; /* information about the remote peer when connecting to other routers */
|
||||
int remotelen = sizeof(struct sockaddr_in); /* length of the remote address */
|
||||
#ifdef MS_WINDOWS
|
||||
int e;
|
||||
#endif
|
||||
|
||||
news = accept(conn->s,(struct sockaddr *)&remote,&remotelen);
|
||||
if (news == -1) { /* accept() error */
|
||||
if(errno==EAGAIN)
|
||||
if(ERRNO_EAGAIN(errno)) {
|
||||
#ifdef MS_WINDOWS
|
||||
e = correct_socket_errno(conn->s);
|
||||
if (ERRNO_EAGAIN(e))
|
||||
return 0;
|
||||
#else
|
||||
return 0; /* he hung up before we could accept(). that's fine. */
|
||||
#endif
|
||||
}
|
||||
/* else there was a real error. */
|
||||
log_fn(LOG_ERR,"accept() failed. Closing.");
|
||||
return -1;
|
||||
|
||||
@@ -265,7 +265,7 @@ int connection_edge_finished_flushing(connection_t *conn) {
|
||||
switch(conn->state) {
|
||||
case EXIT_CONN_STATE_CONNECTING:
|
||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
|
||||
if(errno != EINPROGRESS){
|
||||
if(!ERRNO_CONN_EINPROGRESS(errno)) {
|
||||
/* yuck. kill it. */
|
||||
log_fn(LOG_DEBUG,"in-progress exit connect failed. Removing.");
|
||||
return -1;
|
||||
|
||||
@@ -90,7 +90,7 @@ int connection_exit_connect(connection_t *conn) {
|
||||
log_fn(LOG_DEBUG,"Connecting to %s:%u.",conn->address,conn->port);
|
||||
|
||||
if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0) {
|
||||
if(errno != EINPROGRESS){
|
||||
if(!ERRNO_CONN_EINPROGRESS(errno)) {
|
||||
/* yuck. kill it. */
|
||||
perror("connect");
|
||||
log_fn(LOG_DEBUG,"Connect failed.");
|
||||
@@ -102,7 +102,9 @@ int connection_exit_connect(connection_t *conn) {
|
||||
conn->state = EXIT_CONN_STATE_CONNECTING;
|
||||
|
||||
log_fn(LOG_DEBUG,"connect in progress, socket %d.",s);
|
||||
connection_watch_events(conn, POLLOUT | POLLIN);
|
||||
connection_watch_events(conn, POLLOUT | POLLIN | POLLERR);
|
||||
/* writable indicates finish, readable indicates broken link,
|
||||
error indicates broken link in windowsland. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ int connection_or_finished_flushing(connection_t *conn) {
|
||||
return or_handshake_op_finished_sending_keys(conn);
|
||||
case OR_CONN_STATE_CLIENT_CONNECTING:
|
||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
|
||||
if(errno != EINPROGRESS){
|
||||
if(!ERRNO_CONN_EINPROGRESS(errno)){
|
||||
/* yuck. kill it. */
|
||||
log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
|
||||
return -1;
|
||||
@@ -156,7 +156,7 @@ connection_t *connection_or_connect(routerinfo_t *router) {
|
||||
|
||||
log(LOG_DEBUG,"connection_or_connect() : Trying to connect to %s:%u.",router->address,router->or_port);
|
||||
if(connect(s,(struct sockaddr *)&router_addr,sizeof(router_addr)) < 0){
|
||||
if(errno != EINPROGRESS){
|
||||
if(!ERRNO_CONN_EINPROGRESS(errno)) {
|
||||
/* yuck. kill it. */
|
||||
connection_free(conn);
|
||||
return NULL;
|
||||
@@ -170,7 +170,9 @@ connection_t *connection_or_connect(routerinfo_t *router) {
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"connection_or_connect() : connect in progress.");
|
||||
connection_watch_events(conn, POLLIN | POLLOUT); /* writable indicates finish, readable indicates broken link */
|
||||
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
|
||||
/* writable indicates finish, readable indicates broken link,
|
||||
error indicates broken link on windows */
|
||||
conn->state = OR_CONN_STATE_CLIENT_CONNECTING;
|
||||
return conn;
|
||||
}
|
||||
|
||||
+5
-3
@@ -66,7 +66,7 @@ void directory_initiate_fetch(routerinfo_t *router) {
|
||||
log_fn(LOG_DEBUG,"Trying to connect to %s:%u.",router->address,router->dir_port);
|
||||
|
||||
if(connect(s,(struct sockaddr *)&router_addr,sizeof(router_addr)) < 0){
|
||||
if(errno != EINPROGRESS){
|
||||
if(!ERRNO_CONN_EINPROGRESS(errno)) {
|
||||
/* yuck. kill it. */
|
||||
router_forget_router(conn->addr, conn->port); /* don't try him again */
|
||||
connection_free(conn);
|
||||
@@ -81,7 +81,9 @@ void directory_initiate_fetch(routerinfo_t *router) {
|
||||
}
|
||||
|
||||
log_fn(LOG_DEBUG,"connect in progress.");
|
||||
connection_watch_events(conn, POLLIN | POLLOUT); /* writable indicates finish, readable indicates broken link */
|
||||
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
|
||||
/* writable indicates finish, readable indicates broken link,
|
||||
error indicates broken link in windowsland. */
|
||||
conn->state = DIR_CONN_STATE_CONNECTING;
|
||||
return;
|
||||
}
|
||||
@@ -255,7 +257,7 @@ int connection_dir_finished_flushing(connection_t *conn) {
|
||||
switch(conn->state) {
|
||||
case DIR_CONN_STATE_CONNECTING:
|
||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
|
||||
if(errno != EINPROGRESS){
|
||||
if(!ERRNO_CONN_EINPROGRESS(errno)) {
|
||||
/* yuck. kill it. */
|
||||
log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
|
||||
router_forget_router(conn->addr, conn->port); /* don't try him again */
|
||||
|
||||
+15
-6
@@ -243,7 +243,6 @@ void connection_start_writing(connection_t *conn) {
|
||||
poll_array[conn->poll_index].events |= POLLOUT;
|
||||
}
|
||||
|
||||
|
||||
static void conn_read(int i) {
|
||||
int retval;
|
||||
connection_t *conn;
|
||||
@@ -252,6 +251,13 @@ static void conn_read(int i) {
|
||||
assert(conn);
|
||||
// log_fn(LOG_DEBUG,"socket %d has something to read.",conn->s);
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
if (poll_array[i].revents & POLLERR) {
|
||||
retval = -1;
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (conn->type == CONN_TYPE_OR_LISTENER) {
|
||||
retval = connection_or_handle_listener_read(conn);
|
||||
} else if (conn->type == CONN_TYPE_AP_LISTENER) {
|
||||
@@ -274,14 +280,17 @@ static void conn_read(int i) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
error:
|
||||
#endif
|
||||
if(retval < 0) { /* this connection is broken. remove it */
|
||||
log_fn(LOG_INFO,"%s connection broken, removing.", conn_type_to_string[conn->type]);
|
||||
connection_remove(conn);
|
||||
connection_free(conn);
|
||||
if(i<nfds) { /* we just replaced the one at i with a new one.
|
||||
process it too. */
|
||||
if(poll_array[i].revents & POLLIN ||
|
||||
poll_array[i].revents & POLLHUP ) /* something to read */
|
||||
if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR))
|
||||
/* something to read */
|
||||
conn_read(i);
|
||||
}
|
||||
}
|
||||
@@ -565,10 +574,10 @@ static int do_main_loop(void) {
|
||||
}
|
||||
|
||||
if(poll_result > 0) { /* we have at least one connection to deal with */
|
||||
/* do all the reads first, so we can detect closed sockets */
|
||||
/* do all the reads and errors first, so we can detect closed sockets */
|
||||
for(i=0;i<nfds;i++)
|
||||
if(poll_array[i].revents & POLLIN ||
|
||||
poll_array[i].revents & POLLHUP ) /* something to read */
|
||||
if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR))
|
||||
/* something to read, or an error. */
|
||||
conn_read(i); /* this also blows away broken connections */
|
||||
/* see http://www.greenend.org.uk/rjk/2001/06/poll.html for discussion
|
||||
* of POLLIN vs POLLHUP */
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
#include "../common/crypto.h"
|
||||
#include "../common/log.h"
|
||||
#include "../common/util.h"
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MS_WINDOWS
|
||||
/* For mkdir() */
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user