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; }