openlldp-0.4alpha实现详解(七)——lldp_main,lldpneighbors模块

lldp_main.c模块

调用之前的各个模块的接口,实现lldp功能。使用select进行套接字的复用,每个一秒运行一次端口发送和接收状态机。

#ifdef BUILD_SERVICE
// We are building as a service, so this should be our ServiceMain()
int ServiceMain(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif // BUILD_SERVICE
{
#ifndef WIN32//------------------l--------------------------
    uid_t uid;
    struct timeval timeout;
    struct timeval un_timeout;
    int fork = 1;
#endif 
    int op = 0;
    char *theOpts = "i:d:fshl:o";
    int socket_width = 0;
    time_t current_time = 0;
    time_t last_check = 0;
    int result = 0;
    struct lldp_port *lldp_port = NULL;
	//------------------l--------------------------

#ifdef BUILD_SERVICE//------------------w------------------------
   ServiceStatus.dwServiceType = 
      SERVICE_WIN32; 
   ServiceStatus.dwCurrentState = 
      SERVICE_START_PENDING; 
   ServiceStatus.dwControlsAccepted   =  
      SERVICE_ACCEPT_STOP | 
      SERVICE_ACCEPT_SHUTDOWN;
   ServiceStatus.dwWin32ExitCode = 0; 
   ServiceStatus.dwServiceSpecificExitCode = 0; 
   ServiceStatus.dwCheckPoint = 0; 
   ServiceStatus.dwWaitHint = 0; 
 
   hStatus = RegisterServiceCtrlHandler(
      "OpenLLDP", 
      (LPHANDLER_FUNCTION)ControlHandler); 
   if (hStatus == (SERVICE_STATUS_HANDLE)0) 
   { 
      // Registering Control Handler failed
      return -1; 
   }  
/*	ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
	ServiceStatus.dwWin32ExitCode = 0xfe; 
	SetServiceStatus(hStatus, &ServiceStatus);*/
#endif  // BUILD_SERVICE//------------------w--------------------------

    program = argv[0];

#ifndef WIN32//------------------l--------------------------
    // Process any arguments we were passed in.
    while ((op = getopt(argc, argv, theOpts)) != EOF) {
      switch (op) {
      case 'd':							/*debug 设置调试等级*/
	// Set the debug level.
	if ((atoi(optarg) == 0) && (optarg[0] != '0')) {/*非数字而是字母优先级*/
	  debug_alpha_set_flags(optarg);
	} else {							/*数字优先级*/
	  debug_set_flags(atoi(optarg));
	}
	break;
      case 'i':						   /*interface 使用接口*/
	iface_filter = 1;
	memcpy(iface_list, optarg, strlen(optarg));
	iface_list[IF_NAMESIZE - 1] = '\0';
	debug_printf(DEBUG_NORMAL, "Using interface %s\n", iface_list);
	break;
      case 'l':
#ifdef USE_CONFUSE					/*USE_CONFUSE不懂干嘛的*/
	lci.config_file = optarg;
#else
	debug_printf(DEBUG_NORMAL, "OpenLLDP wasn't compiled with libconfuse support.\n");
	exit(1);
#endif // USE_CONFUSE
	break;
      case 'o':						/*回环接口*/
	// Turn on the looback interface. :)
	process_loopback = 1;
	break;
      case 'f':						/*fork标志应该是只是进程是否fork到后台*/
	fork = 0;
	break;
      case 's':						/*删除sun_path文件*/
	unlink(local.sun_path);
	break;
      case 'h':						/*h暂时无用*/
      default:
	usage();						/*指示用法usage*/
	exit(0);
	break;
      };
    }

	/*
	创建unix的套接字(属于本地ipc)
	主要用于将本进程的信息输出到另一个进程
	*/
    neighbor_local_sd = socket(AF_UNIX, SOCK_STREAM, 0);

    if(neighbor_local_sd < 0)
      {
	debug_printf(DEBUG_NORMAL, "[Error] Unable to open unix domain socket for client registration!\n");
      }

    local.sun_family = AF_UNIX;

	/*
		unix套接字对象路径
	*/
    strcpy(local.sun_path, "/var/run/lldpd.sock");

    debug_printf(DEBUG_NORMAL, "%s:%d\n", local.sun_path, strlen(local.sun_path));


 	/*
 	这里添加一步操作,先删除已经存在的socket文件
 	*/
	unlink(local.sun_path);
    // Bind unix sockets
    result = bind(neighbor_local_sd, (struct sockaddr *)&local, sizeof(local));
																				
    if(result != 0) {
      debug_printf(DEBUG_NORMAL, "[Error] Unable to bind to the unix domain socket for client registration!\n");
    }

	/*
		listen
	*/
    result = listen(neighbor_local_sd, 5);

    if(result != 0) {
      debug_printf(DEBUG_NORMAL, "[Error] Unable to listen to the unix domain socket for client registration!\n");
    }

    // Set the socket permissions
    if(chmod("/var/run/lldpd.sock", S_IWOTH) != 0) {
      debug_printf(DEBUG_NORMAL, "[Error] Unable to set permissions for domain socket!\n");
    }

    /* Needed for select() */
    fd_set readfds;

    fd_set unixfds;

    // get uid of user executing program. 
    uid = getuid();				/*获得pid*/

    if (uid != 0) {
        debug_printf(DEBUG_NORMAL, "You must be running as root to run %s!\n", program);
        exit(0);
    }

#endif // WIN32

	lci.config_file = NULL;

    /* Initialize2 the LLDP subsystem */
    /* This should happen on a per-interface basis */
    if(initializeLLDP() == 0) {/*进行相关初始化工作*/
        debug_printf(DEBUG_NORMAL, "No interface found to listen on\n");
    }

	/*获取本地信息*/
    get_sys_desc();
    get_sys_fqdn();

    #ifdef USE_CONFUSE
    //read the location config file for the first time!
    lci_config ();
    #endif // USE_CONFUSE
	//------------------l--------------------------

#ifdef BUILD_SERVICE//------------------w--------------------------
     // We report the running status to SCM. 
   ServiceStatus.dwCurrentState = 
      SERVICE_RUNNING; 
   SetServiceStatus (hStatus, &ServiceStatus);

   while (ServiceStatus.dwCurrentState == 
          SERVICE_RUNNING)
   {
	   // Sleep for 1 seconds.
	   Sleep(1000);
   }
#endif // BUILD_SERVICE//------------------w--------------------------

#ifndef WIN32

   if (fork) {				/*fork指示是否变为守护进程*/
     if (daemon(0,0) != 0)
       debug_printf(DEBUG_NORMAL, "Unable to daemonize (%m) at: %s():%d\n",
		    __FUNCTION__, __LINE__);
   }
#endif // WIN32

    while(1) {



#ifndef WIN32
      /* Set up the neighbor client domain socket */
      if(neighbor_local_sd > 0) {
	FD_ZERO(&unixfds);	
	FD_SET(neighbor_local_sd, &unixfds);/*将neignbor_local_sd 放入到unixfds描述符集合*/
      } else {
	debug_printf(DEBUG_NORMAL, "Couldn't initialize the socket (%d)\n", neighbor_local_sd);
      }

        /* Set up select() */
        FD_ZERO(&readfds);
#endif // WIN32

        lldp_port = lldp_ports;

        while(lldp_port != NULL) {	/*将所有的套接字都放入readfds里面,然后进行IO复用*/
            // This is not the interface you are looking for...
            if(lldp_port->if_name == NULL)
            {
                debug_printf(DEBUG_NORMAL, "[ERROR] Interface index %d with name is NULL at: %s():%d\n", lldp_port->if_index, __FUNCTION__, __LINE__);
                continue;
            }

#ifndef WIN32
            FD_SET(lldp_port->socket, &readfds);/*lldp_port里面的套接字成员何时被赋值啊? 端口所用的socket用来发送和接收*/

            if(lldp_port->socket > socket_width)/*socket_width为记录套接字最大的值*/
            {
                socket_width = lldp_port->socket;
            }
#endif

            lldp_port = lldp_port->next;

        }

        time(¤t_time);/*记录当前的时间*/

#ifndef WIN32
        // Will be used to tell select how long to wait for...
        timeout.tv_sec = 1;/*等待一秒*/
        timeout.tv_usec = 0;

        // Timeout after 1 second if nothing is ready
        result = select(socket_width+1, &readfds, NULL, NULL, &timeout);/*每个一秒等待数据报文的到达,将该接口的所有数据进行I/O复用*/
#endif // WIN32															

        // Everything is cool... process the sockets
        lldp_port = lldp_ports;										/*等待报文的到达*/

		/*
			循环遍历所有套接字,并且每个端口都执行一步发送/接收状态机
		*/
        while(lldp_port != NULL) {
            // This is not the interface you are looking for...
            if(lldp_port->if_name == NULL) {
                debug_printf(DEBUG_NORMAL, "[ERROR] Interface index %d with name is NULL at: %s():%d\n", lldp_port->if_index, __FUNCTION__, __LINE__);
                continue;/*本次的为空 那么则执行下次循环*/
            }

#ifndef WIN32
            if(result > 0) {/*有数据到达*/
                if(FD_ISSET(lldp_port->socket, &readfds)) {/*测试是不是本次端口套接字可读,若是则执行否则什么也不执行因为没有else分支*/
                    debug_printf(DEBUG_INT, "%s is readable!\n", lldp_port->if_name);

                    // Get the frame back from the OS-specific frame handler.
                    lldp_read(lldp_port);

                    if(lldp_port->rx.recvsize <= 0) {				/*收取数据*/
                        if(errno != EAGAIN && errno != ENETDOWN) {
                            printf("Error: (%d) : %s (%s:%d)\n", errno, strerror(errno), __FUNCTION__, __LINE__);
                        }
                    } else {
                        debug_printf(DEBUG_INT, "Got an LLDP frame %d bytes long on %s!\n", lldp_port->rx.recvsize, lldp_port->if_name);

                        //      debug_hex_dump(DEBUG_INT, lldp_port->rx.frame, lldp_port->rx.recvsize);

                        // Mark that we received a frame so the state machine can process it.
                        lldp_port->rx.rcvFrame = 1;

                        rxStatemachineRun(lldp_port);/*执行数据收取状态机*/  /*估计是在这里面完成MSAP的写入*/
                    }
                }

            }
#endif // WIN32
			/*本接口名非空,但是没数据到达,
			则执行tx 和rx 状态机 
			然后等待本机上其他可执行文件读取其邻居信息*/

            if((result == 0) || (current_time > last_check)) {
                lldp_port->tick = 1;

                txStatemachineRun(lldp_port); 
                rxStatemachineRun(lldp_port);

#ifndef WIN32
		// Will be used to tell select how long to wait for...
		un_timeout.tv_sec  = 0;
		un_timeout.tv_usec = 2;

		/*这次等待主要是等unix套接字是否有连接请求到达*/
		result = select(neighbor_local_sd+1, &unixfds, NULL, NULL, &un_timeout);

		if(result > 0) {
		  if(FD_ISSET(neighbor_local_sd, &unixfds)) {
		    debug_printf(DEBUG_NORMAL, "Got a request on the unix domain socket!\n");

		    socklen_t addrlen = sizeof(remote);

		    neighbor_remote_sd = accept(neighbor_local_sd, (struct sockaddr *)&remote, &addrlen);
		    
		    if(neighbor_remote_sd < 0) {
		      debug_printf(DEBUG_NORMAL, "Couldn't accept remote client socket!\n");
		    } else {
		    	/* 获取邻居信息 */
		      char *client_msg = lldp_neighbor_information(lldp_ports);
			  int bytes_tx = strlen(client_msg);
		      int bytes_sent = 0;

		      while(bytes_tx > 0) {
			
			debug_printf(DEBUG_NORMAL, "Transmitting %d bytes to client...\n", bytes_tx);
			/* 发送 */
			bytes_sent = send(neighbor_remote_sd, client_msg, strlen(client_msg), 0);/*发送*/

			debug_printf(DEBUG_NORMAL, "%d bytes left to send.  Bytes already sent: %d\n\n", bytes_tx, bytes_sent);
		       
			bytes_tx -= bytes_sent;

		      }		    

		      free(client_msg);
		      close(neighbor_remote_sd);		      
		    }
		  }

		}
#endif // WIN32

                lldp_port->tick = 0;
            }

            if(result < 0) {/*result小于0则是出错*/
                if(errno != EINTR) {
                    debug_printf(DEBUG_NORMAL, "[ERROR] %s\n", strerror(errno));
                }
            }

            lldp_port = lldp_port->next;/*下个网卡接口*/

        }

        time(&last_check);     
    }

    return 0;
}
lldpneighbors模块主要为获取主机的邻居信息。

/*******************************************************************
 *
 * OpenLLDP Neighbor 
 *
 * See LICENSE file for more info.
 * 
 * File: lldpneighbors.c
 * 
 * Authors: Terry Simons ([email protected])
 *
 *******************************************************************/

#ifndef WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#endif

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>

#define NEIGHBORLIST_SIZE 512
#define DEBUG 0

int main(int argc, char *argv[]) {   
  char msg[NEIGHBORLIST_SIZE];
  char *buf            = NULL;
  char *tmp            = NULL;
  int s                = 0;
  unsigned int msgSize = 0;
  size_t bytes         = 0;
  int result           = 0;

  buf = calloc(1, NEIGHBORLIST_SIZE);

  memset(&msg[0], 0x0, NEIGHBORLIST_SIZE);

#ifndef WIN32
  struct sockaddr_un addr;

  s = socket(AF_UNIX, SOCK_STREAM, 0);

  addr.sun_family = AF_UNIX;
  /*
  	使用和lldp_main模块一样的unix套接字对象标识
  */
  strcpy(addr.sun_path, "/var/run/lldpd.sock");
  /*
  	连接
  */
  result = connect(s, (struct sockaddr *)&addr, sizeof(addr));

  if(result < 0) {
    printf("\n%s couldn't connect to the OpenLLDP transport socket.  Is lldpd running?\n", argv[0]);
    
    goto cleanup;
  }

  /*
  	接收
  */
  while((bytes = recv(s, msg, NEIGHBORLIST_SIZE, 0))) {
    
    if(bytes > 0) {
      
      tmp = calloc(1, msgSize + bytes + 1);

      if(buf != NULL) {
	memcpy(tmp, buf, msgSize);
	free(buf);
	buf = NULL;
      }
      
      memcpy(&tmp[msgSize], msg, bytes);
      msgSize += bytes;
      
      buf = tmp;
      tmp = NULL;
    } else {
      if(DEBUG) {
	printf("Error reading %d bytes: %d:%s\n", NEIGHBORLIST_SIZE, errno, strerror(errno));
      }
    }
    
    if(DEBUG) {
      printf("Read %d bytes.  Total size is now: %d\n", (int)bytes, msgSize);
      printf("Buffer is: 0x%08X and Temporary Buffer is 0x%08X.\n", (int)&buf, (int)&tmp);
    }
  }

  if(buf != NULL) {
    printf("%s\n", buf);
  }

  
 cleanup:
  if(buf != NULL)
    {
      free(buf);
      msgSize = 0;
      buf = NULL;
    }

  close(s);
#endif

  return 0;
}

本人享有博客文章的版权,转载请标明出处http://blog.csdn.net/baidu20008

你可能感兴趣的:(linux,main,LLDP)