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 (terry.simons@gmail.com)
*
*******************************************************************/
#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