208 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* cygserver_client.cc
 | |
| 
 | |
|    Copyright 2001, 2002 Red Hat Inc.
 | |
| 
 | |
|    Written by Egor Duda <deo@logos-m.ru>
 | |
| 
 | |
|    This file is part of Cygwin.
 | |
| 
 | |
|    This software is a copyrighted work licensed under the terms of the
 | |
|    Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | |
|    details. */
 | |
| 
 | |
| #ifdef __OUTSIDE_CYGWIN__
 | |
| #undef __INSIDE_CYGWIN__
 | |
| #else
 | |
| #include "winsup.h"
 | |
| #endif
 | |
| 
 | |
| #ifndef __INSIDE_CYGWIN__
 | |
| #define debug_printf printf
 | |
| #define api_fatal printf
 | |
| #include <stdio.h>
 | |
| #include <windows.h>
 | |
| #endif
 | |
| #include <sys/socket.h>
 | |
| #include <errno.h>
 | |
| #include <unistd.h>
 | |
| //#include "security.h"
 | |
| #include "cygwin/cygserver_transport.h"
 | |
| #include "cygwin/cygserver_transport_pipes.h"
 | |
| #include "cygwin/cygserver_transport_sockets.h"
 | |
| #include "cygwin/cygserver.h"
 | |
| 
 | |
| /* 0 = untested, 1 = running, 2 = dead */
 | |
| int cygserver_running=CYGSERVER_UNKNOWN;
 | |
| /* on by default during development. For release, we probably want off by default */
 | |
| int allow_daemon = TRUE;
 | |
| 
 | |
| client_request_get_version::client_request_get_version () : client_request (CYGSERVER_REQUEST_GET_VERSION, sizeof (version))
 | |
| {
 | |
|   buffer = (char *)&version;
 | |
| }
 | |
| 
 | |
| client_request_attach_tty::client_request_attach_tty () : client_request (CYGSERVER_REQUEST_ATTACH_TTY, sizeof (req))
 | |
| {
 | |
|   buffer = (char *)&req;
 | |
|   req.pid = 0;
 | |
|   req.master_pid = 0;
 | |
|   req.from_master = NULL;
 | |
|   req.to_master = NULL;
 | |
| }
 | |
| 
 | |
| client_request_attach_tty::client_request_attach_tty (DWORD npid, DWORD nmaster_pid, HANDLE nfrom_master, HANDLE nto_master) : client_request (CYGSERVER_REQUEST_ATTACH_TTY, sizeof (req))
 | |
| {
 | |
|   buffer = (char *)&req;
 | |
|   req.pid = npid;
 | |
|   req.master_pid = nmaster_pid;
 | |
|   req.from_master = nfrom_master;
 | |
|   req.to_master = nto_master;
 | |
| }
 | |
| 
 | |
| client_request_shutdown::client_request_shutdown () : client_request (CYGSERVER_REQUEST_SHUTDOWN, 0)
 | |
| {
 | |
|   buffer = NULL;
 | |
| }
 | |
| 
 | |
| client_request::client_request (cygserver_request_code id, ssize_t buffer_size) : header (id, buffer_size)
 | |
| {
 | |
| }
 | |
| 
 | |
| client_request::~client_request ()
 | |
| {
 | |
| }
 | |
| 
 | |
| client_request::operator class request_header ()
 | |
| {
 | |
|   return header;
 | |
| }
 | |
| 
 | |
| void
 | |
| client_request::send (transport_layer_base *conn)
 | |
| {
 | |
|   if (!conn)
 | |
|     return;
 | |
|   debug_printf("this=%p, conn=%p\n",this, conn);
 | |
|   ssize_t bytes_written, bytes_read;
 | |
|   debug_printf("header.cb = %ld\n",header.cb);
 | |
|   if ((bytes_written = conn->write ((char *)&header, sizeof (header)))
 | |
|     != sizeof(header) || (header.cb &&
 | |
|     (bytes_written = conn->write (buffer, header.cb)) != header.cb))
 | |
|     {
 | |
|       header.error_code = -1;
 | |
|       debug_printf ("bytes written != request size\n");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   debug_printf("Sent request, size (%ld)\n",bytes_written);
 | |
| 
 | |
|   if ((bytes_read = conn->read ((char *)&header, sizeof (header)))
 | |
|     != sizeof (header) || (header.cb &&
 | |
|     (bytes_read = conn->read (buffer, header.cb)) != header.cb))
 | |
|     {
 | |
|       header.error_code = -1;
 | |
|       debug_printf("failed reading response \n");
 | |
|       return;
 | |
|     }
 | |
|   debug_printf ("completed ok\n");
 | |
| }
 | |
| 
 | |
| /* Oh, BTW: Fix the procedural basis and make this more intuitive. */
 | |
| 
 | |
| int
 | |
| cygserver_request (client_request * req)
 | |
| {
 | |
|   class transport_layer_base *transport;
 | |
| 
 | |
|   if (!req || allow_daemon != TRUE)
 | |
|     return -1;
 | |
| 
 | |
|   /* dont' retry every request if the server's not there */
 | |
|   if (cygserver_running==CYGSERVER_DEAD && req->header.req_id != CYGSERVER_REQUEST_GET_VERSION)
 | |
|     return -1;
 | |
| 
 | |
|   transport = create_server_transport ();
 | |
| 
 | |
|   /* FIXME: have at most one connection per thread. use TLS to store the details */
 | |
|   /* logic is:
 | |
|    * if not tlskey->conn, new conn,
 | |
|    * then; transport=conn;
 | |
|    */
 | |
|   if (!transport->connect ())
 | |
|     {
 | |
|       delete transport;
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   debug_printf ("connected to server %p\n", transport);
 | |
| 
 | |
|   req->send(transport);
 | |
| 
 | |
|   transport->close ();
 | |
| 
 | |
|   delete transport;
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| BOOL
 | |
| check_cygserver_available ()
 | |
| {
 | |
|   BOOL ret_val = FALSE;
 | |
|   HANDLE pipe = CreateFile (pipe_name,
 | |
| 			    GENERIC_READ | GENERIC_WRITE,
 | |
| 			    FILE_SHARE_READ | FILE_SHARE_WRITE,
 | |
| 			    &sec_all_nih,
 | |
| 			    OPEN_EXISTING,
 | |
| 			    0,
 | |
| 			    NULL);
 | |
|   if (pipe != INVALID_HANDLE_VALUE || GetLastError () != ERROR_PIPE_BUSY)
 | |
|     ret_val = TRUE;
 | |
| 
 | |
|   if (pipe && pipe != INVALID_HANDLE_VALUE)
 | |
|     CloseHandle (pipe);
 | |
| 
 | |
|   return (ret_val);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void
 | |
| cygserver_init ()
 | |
| {
 | |
|   int rc;
 | |
|   if (allow_daemon != TRUE)
 | |
|     {
 | |
|       cygserver_running = CYGSERVER_DEAD;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   if (cygserver_running==CYGSERVER_OK)
 | |
|     return;
 | |
| 
 | |
|   client_request_get_version *req =
 | |
| 	new client_request_get_version ();
 | |
| 
 | |
|   rc = cygserver_request (req);
 | |
|   delete req;
 | |
|   if (rc < 0)
 | |
|     cygserver_running = CYGSERVER_DEAD;
 | |
|   else if (rc > 0)
 | |
|     api_fatal ("error connecting to cygwin server. error: %d", rc);
 | |
|   else if (req->version.major != CYGWIN_SERVER_VERSION_MAJOR ||
 | |
| 	   req->version.api != CYGWIN_SERVER_VERSION_API ||
 | |
| 	   req->version.minor > CYGWIN_SERVER_VERSION_MINOR)
 | |
|     api_fatal ("incompatible version of cygwin server.\n\
 | |
|  client version %d.%d.%d.%d, server version%ld.%ld.%ld.%ld",
 | |
|     CYGWIN_SERVER_VERSION_MAJOR,
 | |
|     CYGWIN_SERVER_VERSION_API,
 | |
|     CYGWIN_SERVER_VERSION_MINOR,
 | |
|     CYGWIN_SERVER_VERSION_PATCH,
 | |
|     req->version.major,
 | |
|     req->version.api,
 | |
|     req->version.minor,
 | |
|     req->version.patch);
 | |
|   else
 | |
|     cygserver_running = CYGSERVER_OK;
 | |
| }
 |