/*********************************************************************** * server_init_thread * * Send an init thread request. Return 0 if OK. */ size_t server_init_thread( int unix_pid, int unix_tid, void *entry_point ) { int ret; int reply_pipe[2]; struct sigaction sig_act; size_t info_size; sig_act.sa_handler = SIG_IGN; sig_act.sa_flags = 0; sigemptyset( &sig_act.sa_mask ); /* ignore SIGPIPE so that we get an EPIPE error instead */ sigaction( SIGPIPE, &sig_act, NULL ); /* automatic child reaping to avoid zombies */ #ifdef SA_NOCLDWAIT sig_act.sa_flags |= SA_NOCLDWAIT; #endif sigaction( SIGCHLD, &sig_act, NULL ); /* create the server->client communication pipes */ if (pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" ); if (pipe( ntdll_get_thread_data()->wait_fd ) == -1) server_protocol_perror( "pipe" ); wine_server_send_fd( reply_pipe[1] ); wine_server_send_fd( ntdll_get_thread_data()->wait_fd[1] ); ntdll_get_thread_data()->reply_fd = reply_pipe[0]; close( reply_pipe[1] ); /* set close on exec flag */ fcntl( ntdll_get_thread_data()->reply_fd, F_SETFD, 1 ); fcntl( ntdll_get_thread_data()->wait_fd[0], F_SETFD, 1 ); fcntl( ntdll_get_thread_data()->wait_fd[1], F_SETFD, 1 ); SERVER_START_REQ( init_thread ) { req->unix_pid = unix_pid; req->unix_tid = unix_tid; req->teb = wine_server_client_ptr( NtCurrentTeb() ); req->peb = wine_server_client_ptr( NtCurrentTeb()->Peb ); req->entry = wine_server_client_ptr( entry_point ); req->reply_fd = reply_pipe[1]; req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; req->debug_level = (TRACE_ON(server) != 0); ret = wine_server_call( req ); NtCurrentTeb()->ClientId.UniqueProcess = ULongToHandle(reply->pid); NtCurrentTeb()->ClientId.UniqueThread = ULongToHandle(reply->tid); info_size = reply->info_size; server_start_time = reply->server_start; } SERVER_END_REQ; if (ret) server_protocol_error( "init_thread failed with status %x\n", ret ); return info_size; }
/*********************************************************************** * send_request * * Send a request to the server. */ static unsigned int send_request( const struct __server_request_info *req ) { unsigned int i; int ret; if (!req->u.req.request_header.request_size) { if ((ret = write( ntdll_get_thread_data()->request_fd, &req->u.req, sizeof(req->u.req) )) == sizeof(req->u.req)) return STATUS_SUCCESS; } else { struct iovec vec[__SERVER_MAX_DATA+1]; vec[0].iov_base = (void *)&req->u.req; vec[0].iov_len = sizeof(req->u.req); for (i = 0; i < req->data_count; i++) { vec[i+1].iov_base = (void *)req->data[i].ptr; vec[i+1].iov_len = req->data[i].size; } if ((ret = writev( ntdll_get_thread_data()->request_fd, vec, i+1 )) == req->u.req.request_header.request_size + sizeof(req->u.req)) return STATUS_SUCCESS; } if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); if (errno == EPIPE) server_abort_thread(0); if (errno == EFAULT) return STATUS_ACCESS_VIOLATION; server_protocol_perror( "write" ); }
/*********************************************************************** * receive_fd * * Receive a file descriptor passed from the server. */ static int receive_fd( obj_handle_t *handle ) { struct iovec vec; struct msghdr msghdr; int ret, fd = -1; #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS msghdr.msg_accrights = (void *)&fd; msghdr.msg_accrightslen = sizeof(fd); #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ char cmsg_buffer[256]; msghdr.msg_control = cmsg_buffer; msghdr.msg_controllen = sizeof(cmsg_buffer); msghdr.msg_flags = 0; #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &vec; msghdr.msg_iovlen = 1; vec.iov_base = (void *)handle; vec.iov_len = sizeof(*handle); for (;;) { if ((ret = recvmsg( fd_socket, &msghdr, MSG_CMSG_CLOEXEC )) > 0) { #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR( &msghdr ); cmsg; cmsg = CMSG_NXTHDR( &msghdr, cmsg )) { if (cmsg->cmsg_level != SOL_SOCKET) continue; if (cmsg->cmsg_type == SCM_RIGHTS) fd = *(int *)CMSG_DATA(cmsg); #ifdef SCM_CREDENTIALS else if (cmsg->cmsg_type == SCM_CREDENTIALS) { struct ucred *ucred = (struct ucred *)CMSG_DATA(cmsg); server_pid = ucred->pid; } #endif } #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ if (fd != -1) fcntl( fd, F_SETFD, FD_CLOEXEC ); /* in case MSG_CMSG_CLOEXEC is not supported */ return fd; } if (!ret) break; if (errno == EINTR) continue; if (errno == EPIPE) break; server_protocol_perror("recvmsg"); } /* the server closed the connection; time to die... */ abort_thread(0); }
/*********************************************************************** * receive_fd * * Receive a file descriptor passed from the server. */ static int receive_fd( obj_handle_t *handle ) { struct iovec vec; int ret, fd; #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS struct msghdr msghdr; fd = -1; msghdr.msg_accrights = (void *)&fd; msghdr.msg_accrightslen = sizeof(fd); #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ struct msghdr msghdr; struct cmsg_fd cmsg; cmsg.header.len = sizeof(cmsg.header) + sizeof(fd); cmsg.header.level = SOL_SOCKET; cmsg.header.type = SCM_RIGHTS; cmsg.fd = -1; msghdr.msg_control = &cmsg; msghdr.msg_controllen = sizeof(cmsg.header) + sizeof(fd); msghdr.msg_flags = 0; #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &vec; msghdr.msg_iovlen = 1; vec.iov_base = (void *)handle; vec.iov_len = sizeof(*handle); for (;;) { if ((ret = recvmsg( fd_socket, &msghdr, 0 )) > 0) { #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS fd = cmsg.fd; #endif if (fd != -1) fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ return fd; } if (!ret) break; if (errno == EINTR) continue; if (errno == EPIPE) break; server_protocol_perror("recvmsg"); } /* the server closed the connection; time to die... */ server_abort_thread(0); }
/*********************************************************************** * wine_server_send_fd (NTDLL.@) * * Send a file descriptor to the server. * * PARAMS * fd [I] file descriptor to send * * RETURNS * nothing */ void CDECL wine_server_send_fd( int fd ) { struct send_fd data; struct msghdr msghdr; struct iovec vec; int ret; #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS msghdr.msg_accrights = (void *)&fd; msghdr.msg_accrightslen = sizeof(fd); #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ char cmsg_buffer[256]; struct cmsghdr *cmsg; msghdr.msg_control = cmsg_buffer; msghdr.msg_controllen = sizeof(cmsg_buffer); msghdr.msg_flags = 0; cmsg = CMSG_FIRSTHDR( &msghdr ); cmsg->cmsg_len = CMSG_LEN( sizeof(fd) ); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = fd; msghdr.msg_controllen = cmsg->cmsg_len; #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &vec; msghdr.msg_iovlen = 1; vec.iov_base = (void *)&data; vec.iov_len = sizeof(data); data.tid = GetCurrentThreadId(); data.fd = fd; for (;;) { if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return; if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); if (errno == EINTR) continue; if (errno == EPIPE) abort_thread(0); server_protocol_perror( "sendmsg" ); } }
/*********************************************************************** * wine_server_send_fd (NTDLL.@) * * Send a file descriptor to the server. * * PARAMS * fd [I] file descriptor to send * * RETURNS * nothing */ void CDECL wine_server_send_fd( int fd ) { #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS struct cmsg_fd cmsg; #endif struct send_fd data; struct msghdr msghdr; struct iovec vec; int ret; vec.iov_base = (void *)&data; vec.iov_len = sizeof(data); msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &vec; msghdr.msg_iovlen = 1; #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS msghdr.msg_accrights = (void *)&fd; msghdr.msg_accrightslen = sizeof(fd); #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ cmsg.header.len = sizeof(cmsg.header) + sizeof(fd); cmsg.header.level = SOL_SOCKET; cmsg.header.type = SCM_RIGHTS; cmsg.fd = fd; msghdr.msg_control = &cmsg; msghdr.msg_controllen = sizeof(cmsg.header) + sizeof(fd); msghdr.msg_flags = 0; #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ data.tid = GetCurrentThreadId(); data.fd = fd; for (;;) { if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return; if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); if (errno == EINTR) continue; if (errno == EPIPE) server_abort_thread(0); server_protocol_perror( "sendmsg" ); } }
/*********************************************************************** * read_reply_data * * Read data from the reply buffer; helper for wait_reply. */ static void read_reply_data( void *buffer, size_t size ) { int ret; for (;;) { if ((ret = read( ntdll_get_thread_data()->reply_fd, buffer, size )) > 0) { if (!(size -= ret)) return; buffer = (char *)buffer + ret; continue; } if (!ret) break; if (errno == EINTR) continue; if (errno == EPIPE) break; server_protocol_perror("read"); } /* the server closed the connection; time to die... */ server_abort_thread(0); }
/*********************************************************************** * server_init_thread * * Send an init thread request. Return 0 if OK. */ size_t server_init_thread( void *entry_point ) { static const int is_win64 = (sizeof(void *) > sizeof(int)); const char *arch = getenv( "WINEARCH" ); int ret; int reply_pipe[2]; struct sigaction sig_act; size_t info_size; sig_act.sa_handler = SIG_IGN; sig_act.sa_flags = 0; sigemptyset( &sig_act.sa_mask ); /* ignore SIGPIPE so that we get an EPIPE error instead */ sigaction( SIGPIPE, &sig_act, NULL ); /* create the server->client communication pipes */ if (server_pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" ); if (server_pipe( ntdll_get_thread_data()->wait_fd ) == -1) server_protocol_perror( "pipe" ); wine_server_send_fd( reply_pipe[1] ); wine_server_send_fd( ntdll_get_thread_data()->wait_fd[1] ); ntdll_get_thread_data()->reply_fd = reply_pipe[0]; close( reply_pipe[1] ); SERVER_START_REQ( init_thread ) { req->unix_pid = getpid(); req->unix_tid = get_unix_tid(); req->teb = wine_server_client_ptr( NtCurrentTeb() ); req->entry = wine_server_client_ptr( entry_point ); req->reply_fd = reply_pipe[1]; req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; req->debug_level = (TRACE_ON(server) != 0); req->cpu = client_cpu; ret = wine_server_call( req ); NtCurrentTeb()->ClientId.UniqueProcess = ULongToHandle(reply->pid); NtCurrentTeb()->ClientId.UniqueThread = ULongToHandle(reply->tid); info_size = reply->info_size; server_start_time = reply->server_start; server_cpus = reply->all_cpus; } SERVER_END_REQ; is_wow64 = !is_win64 && (server_cpus & (1 << CPU_x86_64)) != 0; ntdll_get_thread_data()->wow64_redir = is_wow64; switch (ret) { case STATUS_SUCCESS: if (arch) { if (!strcmp( arch, "win32" ) && (is_win64 || is_wow64)) fatal_error( "WINEARCH set to win32 but '%s' is a 64-bit installation.\n", wine_get_config_dir() ); if (!strcmp( arch, "win64" ) && !is_win64 && !is_wow64) fatal_error( "WINEARCH set to win64 but '%s' is a 32-bit installation.\n", wine_get_config_dir() ); } return info_size; case STATUS_NOT_REGISTRY_FILE: fatal_error( "'%s' is a 32-bit installation, it cannot support 64-bit applications.\n", wine_get_config_dir() ); case STATUS_NOT_SUPPORTED: if (is_win64) fatal_error( "wineserver is 32-bit, it cannot support 64-bit applications.\n" ); else fatal_error( "'%s' is a 64-bit installation, it cannot be used with a 32-bit wineserver.\n", wine_get_config_dir() ); default: server_protocol_error( "init_thread failed with status %x\n", ret ); } }
/*********************************************************************** * server_init_thread * * Send an init thread request. Return 0 if OK. */ size_t server_init_thread( int unix_pid, int unix_tid, void *entry_point ) { int version, ret; int reply_pipe[2]; struct sigaction sig_act; size_t info_size; sig_act.sa_handler = SIG_IGN; sig_act.sa_flags = 0; sigemptyset( &sig_act.sa_mask ); /* ignore SIGPIPE so that we get an EPIPE error instead */ sigaction( SIGPIPE, &sig_act, NULL ); /* automatic child reaping to avoid zombies */ #ifdef SA_NOCLDWAIT sig_act.sa_flags |= SA_NOCLDWAIT; #endif sigaction( SIGCHLD, &sig_act, NULL ); /* create the server->client communication pipes */ if (pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" ); if (pipe( ntdll_get_thread_data()->wait_fd ) == -1) server_protocol_perror( "pipe" ); wine_server_send_fd( reply_pipe[1] ); wine_server_send_fd( ntdll_get_thread_data()->wait_fd[1] ); ntdll_get_thread_data()->reply_fd = reply_pipe[0]; close( reply_pipe[1] ); /* set close on exec flag */ fcntl( ntdll_get_thread_data()->reply_fd, F_SETFD, 1 ); fcntl( ntdll_get_thread_data()->wait_fd[0], F_SETFD, 1 ); fcntl( ntdll_get_thread_data()->wait_fd[1], F_SETFD, 1 ); SERVER_START_REQ( init_thread ) { req->unix_pid = unix_pid; req->unix_tid = unix_tid; req->teb = NtCurrentTeb(); req->peb = NtCurrentTeb()->Peb; req->entry = entry_point; req->ldt_copy = &wine_ldt_copy; req->reply_fd = reply_pipe[1]; req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; req->debug_level = (TRACE_ON(server) != 0); ret = wine_server_call( req ); NtCurrentTeb()->ClientId.UniqueProcess = ULongToHandle(reply->pid); NtCurrentTeb()->ClientId.UniqueThread = ULongToHandle(reply->tid); info_size = reply->info_size; version = reply->version; server_start_time = reply->server_start; } SERVER_END_REQ; if (ret) server_protocol_error( "init_thread failed with status %x\n", ret ); if (version != SERVER_PROTOCOL_VERSION) server_protocol_error( "version mismatch %d/%d.\n" "Your %s binary was not upgraded correctly,\n" "or you have an older one somewhere in your PATH.\n" "Or maybe the wrong wineserver is still running?\n", version, SERVER_PROTOCOL_VERSION, (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); return info_size; }