server: Use an enum to store socket connection state.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5eaba82a77
commit
a7577014fa
|
@ -291,11 +291,6 @@ extern "C" {
|
|||
#define FD_ROUTING_INTERFACE_CHANGE 0x00000100
|
||||
#define FD_ADDRESS_LIST_CHANGE 0x00000200
|
||||
|
||||
#ifdef __WINESRC__
|
||||
#define FD_WINE_LISTENING 0x10000000
|
||||
#define FD_WINE_CONNECTED 0x40000000
|
||||
#endif
|
||||
|
||||
/* Constants for LPCONDITIONPROC */
|
||||
#define CF_ACCEPT 0x0000
|
||||
#define CF_REJECT 0x0001
|
||||
|
|
143
server/sock.c
143
server/sock.c
|
@ -131,11 +131,20 @@ struct connect_req
|
|||
unsigned int addr_len, send_len, send_cursor;
|
||||
};
|
||||
|
||||
enum connection_state
|
||||
{
|
||||
SOCK_LISTENING,
|
||||
SOCK_UNCONNECTED,
|
||||
SOCK_CONNECTING,
|
||||
SOCK_CONNECTED,
|
||||
SOCK_CONNECTIONLESS,
|
||||
};
|
||||
|
||||
struct sock
|
||||
{
|
||||
struct object obj; /* object header */
|
||||
struct fd *fd; /* socket file descriptor */
|
||||
unsigned int state; /* status bits */
|
||||
enum connection_state state; /* connection state */
|
||||
unsigned int mask; /* event mask */
|
||||
/* pending FD_* events which have not yet been reported to the application */
|
||||
unsigned int pending_events;
|
||||
|
@ -603,8 +612,7 @@ static void complete_async_connect( struct sock *sock )
|
|||
|
||||
sock->pending_events &= ~(FD_CONNECT | FD_READ | FD_WRITE);
|
||||
sock->reported_events &= ~(FD_CONNECT | FD_READ | FD_WRITE);
|
||||
sock->state |= FD_WINE_CONNECTED;
|
||||
sock->state &= ~(FD_CONNECT | FD_WINE_LISTENING);
|
||||
sock->state = SOCK_CONNECTED;
|
||||
|
||||
if (!req->send_len)
|
||||
{
|
||||
|
@ -660,12 +668,12 @@ static int get_poll_flags( struct sock *sock, int event )
|
|||
|
||||
/* A connection-mode socket which has never been connected does not return
|
||||
* write or hangup events, but Linux reports POLLOUT | POLLHUP. */
|
||||
if (sock->type == WS_SOCK_STREAM && !(sock->state & (FD_CONNECT | FD_WINE_CONNECTED | FD_WINE_LISTENING)))
|
||||
if (sock->state == SOCK_UNCONNECTED)
|
||||
event &= ~(POLLOUT | POLLHUP);
|
||||
|
||||
if (event & POLLIN)
|
||||
{
|
||||
if (sock->state & FD_WINE_LISTENING)
|
||||
if (sock->state == SOCK_LISTENING)
|
||||
flags |= AFD_POLL_ACCEPT;
|
||||
else
|
||||
flags |= AFD_POLL_READ;
|
||||
|
@ -674,7 +682,7 @@ static int get_poll_flags( struct sock *sock, int event )
|
|||
flags |= is_oobinline( sock ) ? AFD_POLL_READ : AFD_POLL_OOB;
|
||||
if (event & POLLOUT)
|
||||
flags |= AFD_POLL_WRITE;
|
||||
if (sock->state & FD_WINE_CONNECTED)
|
||||
if (sock->state == SOCK_CONNECTED)
|
||||
flags |= AFD_POLL_CONNECT;
|
||||
if (event & POLLHUP)
|
||||
flags |= AFD_POLL_HUP;
|
||||
|
@ -816,19 +824,25 @@ static void post_socket_event( struct sock *sock, unsigned int event_bit, unsign
|
|||
}
|
||||
}
|
||||
|
||||
static void sock_dispatch_events( struct sock *sock, int prevstate, int event, int error )
|
||||
static void sock_dispatch_events( struct sock *sock, enum connection_state prevstate, int event, int error )
|
||||
{
|
||||
if (prevstate & FD_CONNECT)
|
||||
switch (prevstate)
|
||||
{
|
||||
post_socket_event( sock, FD_CONNECT_BIT, sock_get_error( error ) );
|
||||
goto end;
|
||||
}
|
||||
if (prevstate & FD_WINE_LISTENING)
|
||||
{
|
||||
post_socket_event( sock, FD_ACCEPT_BIT, sock_get_error( error ) );
|
||||
goto end;
|
||||
}
|
||||
case SOCK_UNCONNECTED:
|
||||
break;
|
||||
|
||||
case SOCK_CONNECTING:
|
||||
if (event & (POLLOUT | POLLERR | POLLHUP))
|
||||
post_socket_event( sock, FD_CONNECT_BIT, sock_get_error( error ) );
|
||||
break;
|
||||
|
||||
case SOCK_LISTENING:
|
||||
if (event & (POLLIN | POLLERR | POLLHUP))
|
||||
post_socket_event( sock, FD_ACCEPT_BIT, sock_get_error( error ) );
|
||||
break;
|
||||
|
||||
case SOCK_CONNECTED:
|
||||
case SOCK_CONNECTIONLESS:
|
||||
if (event & POLLIN)
|
||||
post_socket_event( sock, FD_READ_BIT, 0 );
|
||||
|
||||
|
@ -838,10 +852,11 @@ static void sock_dispatch_events( struct sock *sock, int prevstate, int event, i
|
|||
if (event & POLLPRI)
|
||||
post_socket_event( sock, FD_OOB_BIT, 0 );
|
||||
|
||||
if (event & (POLLERR|POLLHUP))
|
||||
if (event & (POLLERR | POLLHUP))
|
||||
post_socket_event( sock, FD_CLOSE_BIT, sock_get_error( error ) );
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
sock_wake_up( sock );
|
||||
}
|
||||
|
||||
|
@ -849,7 +864,7 @@ static void sock_poll_event( struct fd *fd, int event )
|
|||
{
|
||||
struct sock *sock = get_fd_user( fd );
|
||||
int hangup_seen = 0;
|
||||
int prevstate = sock->state;
|
||||
enum connection_state prevstate = sock->state;
|
||||
int error = 0;
|
||||
|
||||
assert( sock->obj.ops == &sock_ops );
|
||||
|
@ -859,32 +874,32 @@ static void sock_poll_event( struct fd *fd, int event )
|
|||
/* we may change event later, remove from loop here */
|
||||
if (event & (POLLERR|POLLHUP)) set_fd_events( sock->fd, -1 );
|
||||
|
||||
if (sock->state & FD_CONNECT)
|
||||
switch (sock->state)
|
||||
{
|
||||
case SOCK_UNCONNECTED:
|
||||
break;
|
||||
|
||||
case SOCK_CONNECTING:
|
||||
if (event & (POLLERR|POLLHUP))
|
||||
{
|
||||
/* we didn't get connected? */
|
||||
sock->state &= ~FD_CONNECT;
|
||||
sock->state = SOCK_UNCONNECTED;
|
||||
event &= ~POLLOUT;
|
||||
error = sock_error( fd );
|
||||
}
|
||||
else if (event & POLLOUT)
|
||||
{
|
||||
/* we got connected */
|
||||
sock->state |= FD_WINE_CONNECTED;
|
||||
sock->state &= ~FD_CONNECT;
|
||||
sock->state = SOCK_CONNECTED;
|
||||
sock->connect_time = current_time;
|
||||
}
|
||||
}
|
||||
else if (sock->state & FD_WINE_LISTENING)
|
||||
{
|
||||
/* listening */
|
||||
break;
|
||||
|
||||
case SOCK_LISTENING:
|
||||
if (event & (POLLERR|POLLHUP))
|
||||
error = sock_error( fd );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* normal data flow */
|
||||
break;
|
||||
|
||||
case SOCK_CONNECTED:
|
||||
case SOCK_CONNECTIONLESS:
|
||||
if (sock->type == WS_SOCK_STREAM && (event & POLLIN))
|
||||
{
|
||||
char dummy;
|
||||
|
@ -926,6 +941,7 @@ static void sock_poll_event( struct fd *fd, int event )
|
|||
|
||||
if (hangup_seen)
|
||||
event |= POLLHUP;
|
||||
break;
|
||||
}
|
||||
|
||||
complete_async_polls( sock, event, error );
|
||||
|
@ -952,7 +968,7 @@ static int poll_flags_from_afd( struct sock *sock, int flags )
|
|||
/* A connection-mode socket which has never been connected does
|
||||
* not return write or hangup events, but Linux returns
|
||||
* POLLOUT | POLLHUP. */
|
||||
if (sock->type == WS_SOCK_STREAM && !(sock->state & (FD_CONNECT | FD_WINE_CONNECTED | FD_WINE_LISTENING)))
|
||||
if (sock->state == SOCK_UNCONNECTED)
|
||||
return -1;
|
||||
|
||||
if (flags & (AFD_POLL_READ | AFD_POLL_ACCEPT))
|
||||
|
@ -979,33 +995,37 @@ static int sock_get_poll_events( struct fd *fd )
|
|||
if (!sock->type) /* not initialized yet */
|
||||
return -1;
|
||||
|
||||
/* A connection-mode Windows socket which has never been connected does not
|
||||
* return any events, but Linux returns POLLOUT | POLLHUP. Hence we need to
|
||||
* return -1 here, to prevent the socket from being polled on at all. */
|
||||
if (sock->type == WS_SOCK_STREAM && !(sock->state & (FD_CONNECT | FD_WINE_CONNECTED | FD_WINE_LISTENING)))
|
||||
switch (sock->state)
|
||||
{
|
||||
case SOCK_UNCONNECTED:
|
||||
/* A connection-mode Windows socket which has never been connected does
|
||||
* not return any events, but Linux returns POLLOUT | POLLHUP. Hence we
|
||||
* need to return -1 here, to prevent the socket from being polled on at
|
||||
* all. */
|
||||
return -1;
|
||||
|
||||
if (sock->state & FD_CONNECT)
|
||||
/* connecting, wait for writable */
|
||||
case SOCK_CONNECTING:
|
||||
return POLLOUT;
|
||||
|
||||
if (!list_empty( &sock->accept_list ) || sock->accept_recv_req )
|
||||
case SOCK_LISTENING:
|
||||
if (!list_empty( &sock->accept_list ) || (mask & FD_ACCEPT))
|
||||
ev |= POLLIN;
|
||||
break;
|
||||
|
||||
case SOCK_CONNECTED:
|
||||
case SOCK_CONNECTIONLESS:
|
||||
if (sock->accept_recv_req)
|
||||
{
|
||||
ev |= POLLIN | POLLPRI;
|
||||
ev |= POLLIN;
|
||||
}
|
||||
else if (async_queued( &sock->read_q ))
|
||||
{
|
||||
if (async_waiting( &sock->read_q )) ev |= POLLIN | POLLPRI;
|
||||
}
|
||||
else if (sock->state & FD_WINE_LISTENING)
|
||||
{
|
||||
if (mask & FD_ACCEPT)
|
||||
ev |= POLLIN;
|
||||
}
|
||||
else if (!sock->rd_shutdown && (mask & FD_READ))
|
||||
ev |= POLLIN | POLLPRI;
|
||||
/* We use POLLIN with 0 bytes recv() as FD_CLOSE indication for stream sockets. */
|
||||
else if (sock->type == WS_SOCK_STREAM && (mask & FD_CLOSE) && !(sock->reported_events & FD_READ))
|
||||
else if (sock->state == SOCK_CONNECTED && (mask & FD_CLOSE) && !(sock->reported_events & FD_READ))
|
||||
ev |= POLLIN;
|
||||
|
||||
if (async_queued( &sock->write_q ))
|
||||
|
@ -1013,7 +1033,12 @@ static int sock_get_poll_events( struct fd *fd )
|
|||
if (async_waiting( &sock->write_q )) ev |= POLLOUT;
|
||||
}
|
||||
else if (!sock->wr_shutdown && (mask & FD_WRITE))
|
||||
{
|
||||
ev |= POLLOUT;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_ENTRY( req, &poll_list, struct poll_req, entry )
|
||||
{
|
||||
|
@ -1067,8 +1092,7 @@ static void sock_queue_async( struct fd *fd, struct async *async, int type, int
|
|||
return;
|
||||
}
|
||||
|
||||
if ( ( !( sock->state & (FD_CONNECT|FD_WINE_LISTENING) ) && type == ASYNC_TYPE_READ ) ||
|
||||
( !( sock->state & (FD_CONNECT) ) && type == ASYNC_TYPE_WRITE ) )
|
||||
if (sock->state != SOCK_CONNECTED)
|
||||
{
|
||||
set_error( STATUS_PIPE_DISCONNECTED );
|
||||
return;
|
||||
|
@ -1181,7 +1205,7 @@ static struct sock *create_socket(void)
|
|||
|
||||
if (!(sock = alloc_object( &sock_ops ))) return NULL;
|
||||
sock->fd = NULL;
|
||||
sock->state = 0;
|
||||
sock->state = SOCK_UNCONNECTED;
|
||||
sock->mask = 0;
|
||||
sock->pending_events = 0;
|
||||
sock->reported_events = 0;
|
||||
|
@ -1359,6 +1383,7 @@ static int init_socket( struct sock *sock, int family, int type, int protocol, u
|
|||
}
|
||||
#endif
|
||||
|
||||
sock->state = (type == WS_SOCK_STREAM ? SOCK_UNCONNECTED : SOCK_CONNECTIONLESS);
|
||||
sock->flags = flags;
|
||||
sock->proto = protocol;
|
||||
sock->type = type;
|
||||
|
@ -1423,7 +1448,7 @@ static struct sock *accept_socket( struct sock *sock )
|
|||
}
|
||||
|
||||
/* newly created socket gets the same properties of the listening socket */
|
||||
acceptsock->state = FD_WINE_CONNECTED;
|
||||
acceptsock->state = SOCK_CONNECTED;
|
||||
acceptsock->nonblocking = sock->nonblocking;
|
||||
acceptsock->mask = sock->mask;
|
||||
acceptsock->proto = sock->proto;
|
||||
|
@ -1477,7 +1502,7 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
acceptsock->state |= FD_WINE_CONNECTED;
|
||||
acceptsock->state = SOCK_CONNECTED;
|
||||
acceptsock->pending_events = 0;
|
||||
acceptsock->reported_events = 0;
|
||||
acceptsock->proto = sock->proto;
|
||||
|
@ -1765,8 +1790,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
|
|||
|
||||
sock->pending_events &= ~FD_ACCEPT;
|
||||
sock->reported_events &= ~FD_ACCEPT;
|
||||
sock->state |= FD_WINE_LISTENING;
|
||||
sock->state &= ~(FD_CONNECT | FD_WINE_CONNECTED);
|
||||
sock->state = SOCK_LISTENING;
|
||||
|
||||
/* a listening socket can no longer be accepted into */
|
||||
allow_fd_caching( sock->fd );
|
||||
|
@ -1804,7 +1828,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sock->state & FD_CONNECT)
|
||||
if (sock->state == SOCK_CONNECTING)
|
||||
{
|
||||
/* FIXME: STATUS_ADDRESS_ALREADY_ASSOCIATED probably isn't right,
|
||||
* but there's no status code that maps to WSAEALREADY... */
|
||||
|
@ -1827,8 +1851,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
|
|||
|
||||
if (!ret)
|
||||
{
|
||||
sock->state |= FD_WINE_CONNECTED;
|
||||
sock->state &= ~FD_CONNECT;
|
||||
sock->state = SOCK_CONNECTED;
|
||||
|
||||
if (!send_len) return 1;
|
||||
}
|
||||
|
@ -1836,7 +1859,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
|
|||
if (!(req = mem_alloc( sizeof(*req) )))
|
||||
return 0;
|
||||
|
||||
sock->state |= FD_CONNECT;
|
||||
sock->state = SOCK_CONNECTING;
|
||||
|
||||
if (params->synchronous && sock->nonblocking)
|
||||
{
|
||||
|
@ -1877,7 +1900,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sock->type == WS_SOCK_STREAM && !(sock->state & FD_WINE_CONNECTED))
|
||||
if (sock->state != SOCK_CONNECTED && sock->state != SOCK_CONNECTIONLESS)
|
||||
{
|
||||
set_error( STATUS_INVALID_CONNECTION );
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue