/* create a signal handler */ static struct handler *create_handler( signal_callback callback ) { struct handler *handler; int fd[2]; if (pipe( fd ) == -1) return NULL; if (!(handler = alloc_object( &handler_ops ))) { close( fd[0] ); close( fd[1] ); return NULL; } handler->pipe_write = fd[1]; handler->pending = 0; handler->callback = callback; if (!(handler->fd = create_anonymous_fd( &handler_fd_ops, fd[0], &handler->obj, 0 ))) { release_object( handler ); return NULL; } set_fd_events( handler->fd, POLLIN ); make_object_static( &handler->obj ); return handler; }
/* send a reply to the current thread */ static void send_reply( union generic_reply *reply ) { int ret; if (!current->reply_size) { if ((ret = write( get_unix_fd( current->reply_fd ), reply, sizeof(*reply) )) != sizeof(*reply)) goto error; } else { struct iovec vec[2]; vec[0].iov_base = (void *)reply; vec[0].iov_len = sizeof(*reply); vec[1].iov_base = current->reply_data; vec[1].iov_len = current->reply_size; if ((ret = writev( get_unix_fd( current->reply_fd ), vec, 2 )) < sizeof(*reply)) goto error; if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply)))) { /* couldn't write it all, wait for POLLOUT */ set_fd_events( current->reply_fd, POLLOUT ); set_fd_events( current->request_fd, 0 ); return; } } if (current->reply_data) { free( current->reply_data ); current->reply_data = NULL; } return; error: if (ret >= 0) fatal_protocol_error( current, "partial write %d\n", ret ); else if (errno == EPIPE) kill_thread( current, 0 ); /* normal death */ else fatal_protocol_perror( current, "reply write" ); }
/* write the remaining part of the reply */ void write_reply( struct thread *thread ) { int ret; if ((ret = write( get_unix_fd( thread->reply_fd ), (char *)thread->reply_data + thread->reply_size - thread->reply_towrite, thread->reply_towrite )) >= 0) { if (!(thread->reply_towrite -= ret)) { free( thread->reply_data ); thread->reply_data = NULL; /* sent everything, can go back to waiting for requests */ set_fd_events( thread->request_fd, POLLIN ); set_fd_events( thread->reply_fd, 0 ); } return; } if (errno == EPIPE) kill_thread( thread, 0 ); /* normal death */ else if (errno != EWOULDBLOCK && errno != EAGAIN) fatal_protocol_perror( thread, "reply write" ); }
static int sock_reselect( struct sock *sock ) { int ev = sock_get_poll_events( sock->fd ); if (debug_level) fprintf(stderr,"sock_reselect(%p): new mask %x\n", sock, ev); if (!sock->polling) /* FIXME: should find a better way to do this */ { /* previously unconnected socket, is this reselect supposed to connect it? */ if (!(sock->state & ~FD_WINE_NONBLOCKING)) return 0; /* ok, it is, attach it to the wineserver's main poll loop */ sock->polling = 1; } /* update condition mask */ set_fd_events( sock->fd, ev ); 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" ); set_fd_events( sock->fd, -1 ); } 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; fcntl( client, F_SETFL, O_NONBLOCK ); create_process( client, NULL, 0 ); } }
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 ); }
/* acquire the main server lock */ static void acquire_lock(void) { struct sockaddr_un addr; struct stat st; struct flock fl; int fd, slen, got_lock = 0; fd = create_server_lock(); fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1; if (fcntl( fd, F_SETLK, &fl ) != -1) { /* check for crashed server */ if (stat( server_socket_name, &st ) != -1 && /* there is a leftover socket */ stat( "core", &st ) != -1 && st.st_size) /* and there is a non-empty core file */ { fprintf( stderr, "Warning: a previous instance of the wine server seems to have crashed.\n" "Please run 'gdb %s %s/core',\n" "type 'backtrace' at the gdb prompt and report the results. Thanks.\n\n", server_argv0, wine_get_server_dir() ); } unlink( server_socket_name ); /* we got the lock, we can safely remove the socket */ got_lock = 1; /* in that case we reuse fd without closing it, this ensures * that we hold the lock until the process exits */ } else { switch(errno) { case ENOLCK: break; case EACCES: /* check whether locks work at all on this file system */ if (fcntl( fd, F_GETLK, &fl ) == -1) break; /* fall through */ case EAGAIN: exit(2); /* we didn't get the lock, exit with special status */ default: fatal_perror( "fcntl %s/%s", wine_get_server_dir(), server_lock_name ); } /* it seems we can't use locks on this fs, so we will use the socket existence as lock */ close( fd ); } if ((fd = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" ); addr.sun_family = AF_UNIX; strcpy( addr.sun_path, server_socket_name ); slen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path) + 1; #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN addr.sun_len = slen; #endif if (bind( fd, (struct sockaddr *)&addr, slen ) == -1) { if ((errno == EEXIST) || (errno == EADDRINUSE)) { if (got_lock) fatal_error( "couldn't bind to the socket even though we hold the lock\n" ); exit(2); /* we didn't get the lock, exit with special status */ } fatal_perror( "bind" ); } atexit( socket_cleanup ); chmod( server_socket_name, 0600 ); /* make sure no other user can connect */ if (listen( fd, 5 ) == -1) fatal_perror( "listen" ); if (!(master_socket = alloc_object( &master_socket_ops )) || !(master_socket->fd = create_anonymous_fd( &master_socket_fd_ops, fd, &master_socket->obj, 0 ))) fatal_error( "out of memory\n" ); set_fd_events( master_socket->fd, POLLIN ); make_object_static( &master_socket->obj ); }
/* lock/unlock the master socket to stop accepting new clients */ void lock_master_socket( int locked ) { set_fd_events( master_socket->fd, locked ? 0 : POLLIN ); }