/* wake anybody waiting on the socket event or send the associated message */ static void sock_wake_up( struct sock *sock ) { unsigned int events = sock->pmask & sock->mask; int i; if ( !events ) return; if (sock->event) { if (debug_level) fprintf(stderr, "signalling events %x ptr %p\n", events, sock->event ); set_event( sock->event ); } if (sock->window) { if (debug_level) fprintf(stderr, "signalling events %x win %08x\n", events, sock->window ); for (i = 0; i < FD_MAX_EVENTS; i++) { int event = event_bitorder[i]; if (sock->pmask & (1 << event)) { lparam_t lparam = (1 << event) | (sock_get_error(sock->errors[event]) << 16); post_message( sock->window, sock->message, sock->wparam, lparam ); } } sock->pmask = 0; sock_reselect( sock ); } }
/* accept a socket (creates a new fd) */ static struct sock *accept_socket( obj_handle_t handle ) { struct sock *acceptsock; struct sock *sock; int acceptfd; sock = (struct sock *)get_handle_obj( current->process, handle, FILE_READ_DATA, &sock_ops ); if (!sock) return NULL; if ( sock->deferred ) { acceptsock = sock->deferred; sock->deferred = NULL; } else { if ((acceptfd = accept_new_fd( sock )) == -1) { release_object( sock ); return NULL; } if (!(acceptsock = alloc_object( &sock_ops ))) { close( acceptfd ); release_object( sock ); return NULL; } init_sock( acceptsock ); /* newly created socket gets the same properties of the listening socket */ acceptsock->state = FD_WINE_CONNECTED|FD_READ|FD_WRITE; if (sock->state & FD_WINE_NONBLOCKING) acceptsock->state |= FD_WINE_NONBLOCKING; acceptsock->mask = sock->mask; acceptsock->proto = sock->proto; acceptsock->type = sock->type; acceptsock->family = sock->family; acceptsock->window = sock->window; acceptsock->message = sock->message; if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event ); acceptsock->flags = sock->flags; if (!(acceptsock->fd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj, get_fd_options( sock->fd ) ))) { release_object( acceptsock ); release_object( sock ); return NULL; } } clear_error(); sock->pmask &= ~FD_ACCEPT; sock->hmask &= ~FD_ACCEPT; sock_reselect( sock ); release_object( sock ); return acceptsock; }
/* create a new and unconnected socket */ static struct object *create_socket( int family, int type, int protocol, unsigned int flags ) { struct sock *sock; int sockfd; sockfd = socket( family, type, protocol ); if (debug_level) fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sockfd); if (sockfd == -1) { sock_set_error(); return NULL; } fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ if (!(sock = alloc_object( &sock_ops ))) { close( sockfd ); return NULL; } sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0; sock->mask = 0; sock->hmask = 0; sock->pmask = 0; sock->polling = 0; sock->flags = flags; sock->type = type; sock->family = family; sock->event = NULL; sock->window = 0; sock->message = 0; sock->wparam = 0; sock->deferred = NULL; sock->read_q = NULL; sock->write_q = NULL; memset( sock->errors, 0, sizeof(sock->errors) ); if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj, (flags & WSA_FLAG_OVERLAPPED) ? 0 : FILE_SYNCHRONOUS_IO_NONALERT ))) { release_object( sock ); return NULL; } sock_reselect( sock ); clear_error(); return &sock->obj; }
static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) { int acceptfd; struct fd *newfd; if ( sock->deferred ) { newfd = dup_fd_object( sock->deferred->fd, 0, 0, get_fd_options( acceptsock->fd ) ); if ( !newfd ) return FALSE; set_fd_user( newfd, &sock_fd_ops, &acceptsock->obj ); release_object( sock->deferred ); sock->deferred = NULL; } else { if ((acceptfd = accept_new_fd( sock )) == -1) return FALSE; if (!(newfd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj, get_fd_options( acceptsock->fd ) ))) return FALSE; } acceptsock->state |= FD_WINE_CONNECTED|FD_READ|FD_WRITE; acceptsock->hmask = 0; acceptsock->pmask = 0; acceptsock->polling = 0; acceptsock->type = sock->type; acceptsock->family = sock->family; acceptsock->wparam = 0; acceptsock->deferred = NULL; release_object( acceptsock->fd ); acceptsock->fd = newfd; clear_error(); sock->pmask &= ~FD_ACCEPT; sock->hmask &= ~FD_ACCEPT; sock_reselect( sock ); return TRUE; }
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) { struct sock *sock = get_fd_user( fd ); struct async *async; struct async_queue *queue; assert( sock->obj.ops == &sock_ops ); switch (type) { case ASYNC_TYPE_READ: if (!sock->read_q && !(sock->read_q = create_async_queue( sock->fd ))) return; queue = sock->read_q; break; case ASYNC_TYPE_WRITE: if (!sock->write_q && !(sock->write_q = create_async_queue( sock->fd ))) return; queue = sock->write_q; break; default: set_error( STATUS_INVALID_PARAMETER ); return; } if ( ( !( sock->state & (FD_READ|FD_CONNECT|FD_WINE_LISTENING) ) && type == ASYNC_TYPE_READ ) || ( !( sock->state & (FD_WRITE|FD_CONNECT) ) && type == ASYNC_TYPE_WRITE ) ) { set_error( STATUS_PIPE_DISCONNECTED ); return; } if (!(async = create_async( current, queue, data ))) return; release_object( async ); sock_reselect( sock ); set_error( STATUS_PENDING ); }
static void sock_reselect_async( struct fd *fd, struct async_queue *queue ) { struct sock *sock = get_fd_user( fd ); sock_reselect( sock ); }
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; int error = 0; assert( sock->obj.ops == &sock_ops ); if (debug_level) fprintf(stderr, "socket %p select event: %x\n", sock, 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) { if (event & (POLLERR|POLLHUP)) { /* we didn't get connected? */ sock->state &= ~FD_CONNECT; event &= ~POLLOUT; error = sock_error( fd ); } else if (event & POLLOUT) { /* we got connected */ sock->state |= FD_WINE_CONNECTED|FD_READ|FD_WRITE; sock->state &= ~FD_CONNECT; } } else if (sock->state & FD_WINE_LISTENING) { /* listening */ if (event & (POLLERR|POLLHUP)) error = sock_error( fd ); } else { /* normal data flow */ if ( sock->type == SOCK_STREAM && ( event & POLLIN ) ) { char dummy; int nr; /* Linux 2.4 doesn't report POLLHUP if only one side of the socket * has been closed, so we need to check for it explicitly here */ nr = recv( get_unix_fd( fd ), &dummy, 1, MSG_PEEK ); if ( nr == 0 ) { hangup_seen = 1; event &= ~POLLIN; } else if ( nr < 0 ) { event &= ~POLLIN; /* EAGAIN can happen if an async recv() falls between the server's poll() call and the invocation of this routine */ if ( errno != EAGAIN ) { error = errno; event |= POLLERR; if ( debug_level ) fprintf( stderr, "recv error on socket %p: %d\n", sock, errno ); } } } if ( (hangup_seen || event & (POLLHUP|POLLERR)) && (sock->state & (FD_READ|FD_WRITE)) ) { error = error ? error : sock_error( fd ); if ( (event & POLLERR) || ( sock_shutdown_type == SOCK_SHUTDOWN_EOF && (event & POLLHUP) )) sock->state &= ~FD_WRITE; sock->state &= ~FD_READ; if (debug_level) fprintf(stderr, "socket %p aborted by error %d, event: %x\n", sock, error, event); } if (hangup_seen) event |= POLLHUP; } event = sock_dispatch_asyncs( sock, event, error ); sock_dispatch_events( sock, prevstate, event, error ); /* if anyone is stupid enough to wait on the socket object itself, * maybe we should wake them up too, just in case? */ wake_up( &sock->obj, 0 ); sock_reselect( sock ); }
/* accept a socket (creates a new fd) */ static struct sock *accept_socket( obj_handle_t handle ) { struct sock *acceptsock; struct sock *sock; int acceptfd; struct sockaddr saddr; sock = (struct sock *)get_handle_obj( current->process, handle, FILE_READ_DATA, &sock_ops ); if (!sock) return NULL; if ( sock->deferred ) { acceptsock = sock->deferred; sock->deferred = NULL; } else { /* Try to accept(2). We can't be safe that this an already connected socket * or that accept() is allowed on it. In those cases we will get -1/errno * return. */ unsigned int slen = sizeof(saddr); acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen); if (acceptfd==-1) { sock_set_error(); release_object( sock ); return NULL; } if (!(acceptsock = alloc_object( &sock_ops ))) { close( acceptfd ); release_object( sock ); return NULL; } /* newly created socket gets the same properties of the listening socket */ fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ acceptsock->state = FD_WINE_CONNECTED|FD_READ|FD_WRITE; if (sock->state & FD_WINE_NONBLOCKING) acceptsock->state |= FD_WINE_NONBLOCKING; acceptsock->mask = sock->mask; acceptsock->hmask = 0; acceptsock->pmask = 0; acceptsock->polling = 0; acceptsock->type = sock->type; acceptsock->family = sock->family; acceptsock->event = NULL; acceptsock->window = sock->window; acceptsock->message = sock->message; acceptsock->wparam = 0; if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event ); acceptsock->flags = sock->flags; acceptsock->deferred = NULL; acceptsock->read_q = NULL; acceptsock->write_q = NULL; memset( acceptsock->errors, 0, sizeof(acceptsock->errors) ); if (!(acceptsock->fd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj, get_fd_options( sock->fd ) ))) { release_object( acceptsock ); release_object( sock ); return NULL; } } clear_error(); sock->pmask &= ~FD_ACCEPT; sock->hmask &= ~FD_ACCEPT; sock_reselect( sock ); release_object( sock ); return acceptsock; }