static int sock_get_poll_events( struct fd *fd ) { struct sock *sock = get_fd_user( fd ); unsigned int mask = sock->mask & ~sock->hmask; unsigned int smask = sock->state & mask; int ev = 0; assert( sock->obj.ops == &sock_ops ); if (sock->state & FD_CONNECT) /* connecting, wait for writable */ return POLLOUT; if ( async_queued( sock->read_q ) ) { if ( async_waiting( sock->read_q ) ) ev |= POLLIN | POLLPRI; } else if (smask & FD_READ || (sock->state & FD_WINE_LISTENING && mask & FD_ACCEPT)) ev |= POLLIN | POLLPRI; /* We use POLLIN with 0 bytes recv() as FD_CLOSE indication for stream sockets. */ else if ( sock->type == SOCK_STREAM && sock->state & FD_READ && mask & FD_CLOSE && !(sock->hmask & FD_READ) ) ev |= POLLIN; if ( async_queued( sock->write_q ) ) { if ( async_waiting( sock->write_q ) ) ev |= POLLOUT; } else if (smask & FD_WRITE) ev |= POLLOUT; return ev; }
/* handle a socket event */ static void master_socket_poll_event( struct fd *fd, int event ) { struct master_socket *sock = get_fd_user( fd ); assert( master_socket->obj.ops == &master_socket_ops ); assert( sock == master_socket ); /* there is only one master socket */ if (event & (POLLERR | POLLHUP)) { /* this is not supposed to happen */ fprintf( stderr, "wineserver: Error on master socket\n" ); release_object( sock ); } else if (event & POLLIN) { struct sockaddr_un dummy; unsigned int len = sizeof(dummy); int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len ); if (client == -1) return; if (sock->timeout) { remove_timeout_user( sock->timeout ); sock->timeout = NULL; } fcntl( client, F_SETFL, O_NONBLOCK ); create_process( client, NULL, 0 ); } }
static int file_get_info( struct fd *fd ) { struct file *file = get_fd_user( fd ); if (is_overlapped( file )) return FD_FLAG_OVERLAPPED; else return 0; }
static enum server_fd_type file_get_fd_type( struct fd *fd ) { struct file *file = get_fd_user( fd ); if (S_ISREG(file->mode) || S_ISBLK(file->mode)) return FD_TYPE_FILE; if (S_ISDIR(file->mode)) return FD_TYPE_DIR; return FD_TYPE_CHAR; }
static int file_get_poll_events( struct fd *fd ) { struct file *file = get_fd_user( fd ); int events = 0; assert( file->obj.ops == &file_ops ); if (file->access & FILE_UNIX_READ_ACCESS) events |= POLLIN; if (file->access & FILE_UNIX_WRITE_ACCESS) events |= POLLOUT; return events; }
static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ) { struct sock *sock = get_fd_user( fd ); int n = 0; assert( sock->obj.ops == &sock_ops ); n += async_wake_up_by( sock->read_q, process, thread, iosb, STATUS_CANCELLED ); n += async_wake_up_by( sock->write_q, process, thread, iosb, STATUS_CANCELLED ); if (!n && iosb) set_error( STATUS_NOT_FOUND ); }
static obj_handle_t device_file_flush( struct fd *fd, const async_data_t *async_data, int blocking ) { struct device_file *file = get_fd_user( fd ); struct irp_call *irp; obj_handle_t handle; irp_params_t params; memset( ¶ms, 0, sizeof(params) ); params.flush.major = IRP_MJ_FLUSH_BUFFERS; params.flush.file = file->user_ptr; irp = create_irp( file, ¶ms, NULL, 0, 0 ); if (!irp) return 0; handle = queue_irp( file, irp, async_data, blocking ); release_object( irp ); return handle; }
static void handler_poll_event( struct fd *fd, int event ) { struct handler *handler = get_fd_user( fd ); if (event & (POLLERR | POLLHUP)) { /* this is not supposed to happen */ fprintf( stderr, "wineserver: Error on signal handler pipe\n" ); release_object( handler ); } else if (event & POLLIN) { char dummy; handler->pending = 0; read( get_unix_fd( handler->fd ), &dummy, 1 ); handler->callback(); } }
static obj_handle_t device_file_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, int blocking ) { struct device_file *file = get_fd_user( fd ); struct irp_call *irp; obj_handle_t handle; irp_params_t params; memset( ¶ms, 0, sizeof(params) ); params.ioctl.major = IRP_MJ_DEVICE_CONTROL; params.ioctl.code = code; params.ioctl.file = file->user_ptr; irp = create_irp( file, ¶ms, get_req_data(), get_req_data_size(), get_reply_max_size() ); if (!irp) return 0; handle = queue_irp( file, irp, async_data, blocking ); release_object( irp ); return handle; }
static obj_handle_t device_file_write( struct fd *fd, const async_data_t *async_data, int blocking, file_pos_t pos, data_size_t *written ) { struct device_file *file = get_fd_user( fd ); struct irp_call *irp; obj_handle_t handle; irp_params_t params; memset( ¶ms, 0, sizeof(params) ); params.write.major = IRP_MJ_WRITE; params.write.key = 0; params.write.pos = pos; params.write.file = file->user_ptr; irp = create_irp( file, ¶ms, get_req_data(), get_req_data_size(), 0 ); if (!irp) return 0; handle = queue_irp( file, irp, async_data, blocking ); release_object( irp ); return handle; }
static obj_handle_t device_file_read( struct fd *fd, const async_data_t *async_data, int blocking, file_pos_t pos ) { struct device_file *file = get_fd_user( fd ); struct irp_call *irp; obj_handle_t handle; irp_params_t params; memset( ¶ms, 0, sizeof(params) ); params.read.major = IRP_MJ_READ; params.read.key = 0; params.read.pos = pos; params.read.file = file->user_ptr; irp = create_irp( file, ¶ms, NULL, 0, get_reply_max_size() ); if (!irp) return 0; handle = queue_irp( file, irp, async_data, blocking ); release_object( irp ); return handle; }
static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, int blocking, const void *data, data_size_t size ) { struct device *device = get_fd_user( fd ); struct ioctl_call *ioctl; obj_handle_t handle; if (!device->manager) /* it has been deleted */ { set_error( STATUS_FILE_DELETED ); return 0; } if (!(ioctl = create_ioctl( device, code, data, size, get_reply_max_size() ))) return 0; ioctl->thread = (struct thread *)grab_object( current ); ioctl->user_arg = async_data->arg; if (!(handle = alloc_handle( current->process, ioctl, SYNCHRONIZE, 0 ))) { release_object( ioctl ); return 0; } if (!(ioctl->async = fd_queue_async( device->fd, async_data, ASYNC_TYPE_WAIT ))) { close_handle( current->process, handle ); release_object( ioctl ); return 0; } list_add_tail( &device->requests, &ioctl->dev_entry ); list_add_tail( &device->manager->requests, &ioctl->mgr_entry ); if (list_head( &device->manager->requests ) == &ioctl->mgr_entry) /* first one */ wake_up( &device->manager->obj, 0 ); /* don't release ioctl since it is now queued in the device */ set_error( STATUS_PENDING ); return handle; }
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 ); }