⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xsupgui_ud.c

📁 linux 下通过802.1认证的安装包
💻 C
字号:
/**
 *
 * Licensed under a dual GPL/BSD license. (See LICENSE file for more info.)
 *
 * \file xsupgui_ud.c
 *
 * \author chris@open1x.org, Terry.Simons@utah.edu
 *
 * $Id: xsupgui_ud.c,v 1.1.2.11 2007/07/09 05:47:50 chessing Exp $
 * $Date: 2007/07/09 05:47:50 $
 **/
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <libxml/parser.h>

#include "../../src/xsup_common.h"
#include "../libxsupconfig/xsupconfig_structs.h"
#include "xsupgui_request.h"
#include "xsupgui.h"

#ifdef USE_EFENCE
#include <efence.h>
#endif

#define XSUP_SOCKET "/tmp/xsupplicant.sock"
#define DEBUG  0

#define MAXBUF  4096

int ipc_sock = -1;
int ipc_event_sock = -1;

xmlDocPtr xmlrecvmsg = NULL;        ///< XML Document that represents an async event that we received.

// Some forward decls.
int xsupgui_ud_send_to_event(char *, int);

/**
 * \brief Establish a request/response handler to talk to the supplicant.
 *
 * \retval 0 on success
 * \retval -1 on error
 **/
int xsupgui_ud_connect()
{
  int sockErr;
  struct sockaddr_un sa;

  ipc_sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (ipc_sock < 0)
    {
#if DEBUG
      printf("Error getting socket!\n");
#endif
      return -1;
    }

  Strncpy(sa.sun_path, sizeof(sa.sun_path), XSUP_SOCKET, sizeof(sa.sun_path));

  sa.sun_family = AF_LOCAL;
  
  sockErr = connect(ipc_sock, (struct sockaddr *)&sa, sizeof(sa));
  if (sockErr < 0) 
    {
#if DEBUG
      printf("Socket Error : %d -- %s  (%s:%d)\n", errno, strerror(errno),
	     __FUNCTION__, __LINE__);
#endif
      return errno;
    }

  return 0;
}

/**
 * \brief Establish a connection to the supplicant daemon, and create an
 *        event socket.
 *
 * \retval 0 on success
 * \retval -1 on error
 *
 * \warning A return value of -1 indicates that the supplicant probably
 *          isn't running.  The UI should notify the user of this!
 **/
int xsupgui_ud_connect_event_listener()
{
  int sockErr = 0;
  struct sockaddr_un sa;
  char *result = NULL;
  int ressize = 0;

  ipc_event_sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (ipc_event_sock < 0)
    {
#if DEBUG
      printf("Error getting socket!\n");
#endif
      return -1;
    }

  Strncpy(sa.sun_path, sizeof(sa.sun_path), XSUP_SOCKET, sizeof(sa.sun_path));

  sa.sun_family = AF_LOCAL;

  sockErr = connect(ipc_event_sock, (struct sockaddr *)&sa, sizeof(sa));
  if (sockErr < 0)
    {
#if DEBUG
      printf("Socket Error : %d -- %s  (%s:%d)\n", errno, strerror(errno),
             __FUNCTION__, __LINE__);
#endif
      return errno;
    }

  if (xsupgui_request_set_as_event(&result, &ressize) == REQUEST_FAILURE)
    return -1;

  if (xsupgui_ud_send_to_event(result, ressize) == REQUEST_FAILURE)
    {
      free(result);
      result = NULL;
      return -1;
    }

  free(result);
  return 0;
}

/**
 * \brief Disconnect from the daemon.
 *
 * \retval 0 on success
 * \retval -1 on failure
 **/
int xsupgui_ud_disconnect()
{
  if (ipc_sock != -1) close(ipc_sock);
  return 0;
}

/**
 * \brief Disconnect an event listener socket from the daemon.
 *
 * \retval -1 on failure
 * \retval 0 on success
 **/
int xsupgui_ud_disconnect_event_listener()
{
  if (ipc_event_sock != -1) close(ipc_event_sock);

  return 0;
}

/**
 * \brief  Return the xmlDocPtr that contains the event document.
 *
 * \retval xmlDocPtr containing the event message.  (May be NULL.)
 **/
xmlDocPtr xsupgui_ud_get_event_doc()
{
  return xmlrecvmsg;
}

void xsupgui_ud_free_event_doc()
{
  if (xmlrecvmsg == NULL) return;  // Nothing to do.
  xmlFreeDoc(xmlrecvmsg);
  xmlrecvmsg = NULL;
}

/**
 * \brief Read data from an already connected Unix domain socket.
 *
 * @param[out] result   A buffer to the data that was read.  (This function
 *                      will allocate the memory, the caller is expected to
 *                      free it.)
 * @param[out] resultsize   The amount of data that the buffer contains.
 *
 * \retval 0 on success
 * \retval -1 on error
 * \retval -2 on connection broken.
 **/
int xsupgui_ud_recv_event(unsigned char **result, int *resultsize)
{
  char *resdata = NULL;
  ssize_t cread = 0;
  int retval = 0;

  (*result) = NULL;
  (*resultsize) = 0;

  resdata = malloc(MAXBUF);
  if (resdata == NULL)
    {
      return -1;
    }

  cread = recv(ipc_event_sock, resdata, MAXBUF, 0); 

  if (cread < 0) return -1;   // Got an error.

  if (cread == 0)
    {
      printf("No data available!\n");
      return -2;
    }

  (*resultsize) = cread;
  (*result) = resdata;

  return 0;
}

/**
 * \brief Read data from an already connected Unix domain socket.
 *
 * @param[out] result   A buffer to the data that was read.  (This function
 *                      will allocate memory, the caller is expected to free
 *                      it.)
 * @param[out] resultsize   The amount of data that the buffer contains.
 *
 * \retval 0 on success
 * \retval -1 on error
 * \retval 1 on timeout
 **/
int xsupgui_ud_recv(unsigned char **result, int *resultsize)
{
  unsigned char *resdata = NULL;
  uint8_t *data = NULL;
  ssize_t cread = 0;
  fd_set rfds;
  struct timeval tv;
  int done = FALSE;
  int size = 0;
  int offset = 0;
  ipc_header *hdr = NULL;
  uint32_t value32 = 0;

  if (ipc_sock < 0) return -1;

  resdata = malloc(MAXBUF);
  if (resdata == NULL)
    {
      return -1;
    }

  while (done == FALSE)
    {
      FD_ZERO(&rfds);
      FD_SET(ipc_sock, &rfds);
      
      tv.tv_sec = 2;
      tv.tv_usec = 0;
      
      switch (select(ipc_sock+1, &rfds, 0, 0, &tv))
	{
	case 0:
	  return 1;   // Timeout
	  break;
	  
	case -1:
	  return -1;  // Got an error.
	  break;
	  
	default:
	  // Fall through.
	  break;
	}
      
      cread = recv(ipc_sock, resdata, MAXBUF, 0);

      if (cread == 0)
	{
	  free(resdata);
	  printf("No data available!\n");
	  return -2;
	}

      if (cread < 0)    // Got an error.
	{
	  free(resdata);
	  return -1;
	}

      if (resdata[0] == 0x00)
	{
	  size = (cread - sizeof(ipc_header));

	  if (data == NULL)
	    {
	      data = malloc(size);
	      if (data == NULL)
		{
		  free(resdata);
		  return -1;
		}
	      
	      memset(data, 0x00, size);
	    }
	  
	  memcpy(&data[offset], &resdata[sizeof(ipc_header)], size);
	  
	  free(resdata);
	
	  (*resultsize) = offset + size;
	  (*result) = data;
	  return REQUEST_SUCCESS;
	}

      if ((resdata[0] && IPC_MSG_TOTAL_SIZE) == IPC_MSG_TOTAL_SIZE)
	{
	  // We need to allocate memory.
	  if (data != NULL)
	    {
	      return IPC_ERROR_NOT_INITIALIZED;
	    }

	  hdr = (ipc_header *)&resdata[0];
	  value32 = ntohl(hdr->length);

	  data = malloc(value32);
	  if (data == NULL)
	    {
	      free(resdata);
	      return IPC_ERROR_CANT_MALLOC_LOCAL;
	    }
	  memset(data, 0x00, value32);
	}

      // Copy the data.
      memcpy(&data[offset], &resdata[sizeof(ipc_header)], (size - sizeof(ipc_header)));
      offset += (size - sizeof(ipc_header));
    }

  (*resultsize) = offset;
  (*result) = data;

  return REQUEST_SUCCESS;
}

/**
 * \brief Process events from the supplicant.
 *
 * Catch unsolicited events that are generated by the supplicant.
 *
 * \warning This is a *BLOCKING* call, so it should be run from a different
 *          thread, and signals should be passed back to the core of the UI.
 *          The other alternative is to call xsupgui_selectable_socket() and
 *          use select() to wait for an event.  However, select() doesn't
 *          work with Windows, so if the UI is to be cross platform, it would
 *          be the wrong way to handle it.
 *
 * \retval >1 there is a new event to process.
 * \retval 0 if there is still an event to process
 * \retval -1 on error
 **/
long int xsupgui_ud_process(int *evttype)
{
  int retval = 1;
  char *eventbuf = NULL;
  int eventbufressize = 0;

  // If eventbuf points to something, we have a problem.
  if (xmlrecvmsg != NULL)
    return 0;

  retval = xsupgui_ud_recv_event(&eventbuf, &eventbufressize);

  if (retval != REQUEST_SUCCESS)
    {
      return retval;
    }

  if ((eventbuf == NULL) || ((eventbufressize-5) < 0))
    {
      xmlrecvmsg = NULL;
      if (eventbuf != NULL) free(eventbuf);
      return IPC_ERROR_BAD_RESPONSE_DATA;
    }

  xmlrecvmsg = xmlReadMemory(&eventbuf[5], (eventbufressize-5), "ipc.xml", NULL, 0);
  if (xmlrecvmsg == NULL)
    {
      free(eventbuf);
      return IPC_ERROR_BAD_RESPONSE_DATA;
    }

  if (eventbuf != NULL) free(eventbuf);
  eventbuf = NULL;

  (*evttype) = xsupgui_events_get_event_num(xmlrecvmsg);

  return REQUEST_SUCCESS;
}

/**
 * \brief Return the socket that we created to listen for events.
 *
 * \retval -1 on error
 * \retval >=0 the socket number that can be used with select.
 **/
int xsupgui_ud_selectable_socket()
{
  return ipc_event_sock;
}

/**
 * \brief Send an IPC message via the allocated event socket.
 *
 * This function will send an IPC request to ask that the supplicant treat
 * this socket in a specific way.  (Usually converting it from a 
 * request/response socket to an event socket.)
 *
 * @param[in] buffer   The buffer to be sent down to the event socket.
 * @param[in] bufsize   The size of the buffer to be sent.
 *
 * \retval REQUEST_SUCCESS buffer was sent, and acked
 * \retval REQUEST_FAILURE buffer couldn't be sent, or wasn't acked.
 *
 * \warning This function should *NEVER* be called outside of the libxsupgui
 *          library!  And should *ONLY* be directly called by
 *          \ref xsupgui_send_to_event().
 **/ 
int xsupgui_ud_send_to_event(char *buffer, int bufsize)
{
  int totalbytes = 0;
  unsigned char *result = NULL;
  int resultsize = 0;
  int retval = 0;
  xmlDocPtr indoc = NULL;
  int i = 0;

  totalbytes = send(ipc_event_sock, buffer, bufsize, 0);
  if (totalbytes < 0) return REQUEST_FAILURE;

  if (totalbytes != bufsize) return REQUEST_FAILURE;

  retval = xsupgui_ud_recv_event(&result, &resultsize);
  if (retval != 0) return REQUEST_FAILURE;

  indoc = xsupgui_xml_common_validate_msg(&result[5], (resultsize-5));
  if (indoc == NULL) return REQUEST_FAILURE;

  return xsupgui_request_is_ack(indoc);
}

/**
 * \brief Send an IPC request, and wait for a response.
 *
 * @param[in] tosend   A memory buffer containing the message to be sent to the
 *                     supplicant.
 *
 * @param[in] sendsize   The size of the memory buffer that is being sent.
 *                       (Note : This can't be over 4k!)
 *
 * @param[out] result   The result message generated by the supplicant.  The
 *                      library will allocate the necessary memory to store
 *                      the result, the caller is expected to free it!
 *
 * @param[out] resultsize   A pointer to the size of the result generated by
 *                          the supplicant.
 *
 * \retval REQUEST_SUCCESS for success
 * \retval REQUEST_FAILURE for error
 * \retval REQUEST_TIMEOUT for timeout waiting for a response.
 **/
int xsupgui_ud_send(unsigned char *tosend, int sendsize, unsigned char **result,
		    int *resultsize)
{
  int totalbytes = 0;

  (*result) = NULL;
  (*resultsize) = 0;

  totalbytes = send(ipc_sock, tosend, sendsize, 0);
  if (totalbytes < 0) return REQUEST_FAILURE;

  if (totalbytes != sendsize) return REQUEST_FAILURE;

  return xsupgui_ud_recv(result, resultsize);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -