Files
m241Neelima/components/ip_net2-6.9/ipmip/src/ipmip_cli.c
T
2026-07-30 11:19:44 +05:30

2171 lines
64 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_cli.c,v $ $Revision: 1.23.10.4 $
* $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_cli.c,v $
* $Author: jsheng $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipmip_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_clib2.h>
#include <ipcom_err.h>
#include <ipcom_inet.h>
#include <ipcom_ipd.h>
#include <ipcom_list.h>
#include <ipcom_hash.h>
#include <ipcom_os.h>
#include <ipcom_sock.h>
#include <ipcom_sock.h>
#include <ipcom_sock2.h>
#include <ipcom_sysctl.h>
#include <ipcom_syslog.h>
#include <ipcom_sysvar.h>
#include <ipcom_cmd.h>
#include <ipcom_getopt.h>
#include <ipmip.h>
#include <private/ipmip_util.h>
#include <private/ipmip_buffer.h>
#include <private/ipmip_context.h>
#include <private/ipmip_cli.h>
#include <private/ipmip_util.h>
#include <private/ipmip_sysvar.h>
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPCOM_SYSLOG_PRIORITY IPCOM_LOG_DEBUG2
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPMIP
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipmip_cli_client_mcast
{
Ipcom_list next;
Ip_u32 channel;
} Ipmip_cli_client_mcast_t;
typedef struct Ipmip_cli_client
{
Ipcom_list next;
Ipcom_block block;
Ipmip_proc_t *proc;
/**/
Ipmip_cli_message_t *request;
Ip_fd fd;
/* Connection information */
union Ip_sockaddr_union conn_local;
union Ip_sockaddr_union conn_remote;
Ipmip_cli_context_t *cli;
Ipmip_cli_ident_t ident;
Ipcom_list replies;
Ipcom_list mcasts;
} Ipmip_cli_client_t;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC void
ipmip_cli_config_name_print(Ipmip_proc_t *proc,
Ipmip_cli_daemon_t *daemon,
const char *name)
{
Ipmip_cli_daemon_req_t req;
Ipmip_attr_iter_t riter;
IPMIP_UNUSED_PARAMETER(proc);
ipmip_cli_daemon_request_init(&req);
if (ipmip_cli_config_list(daemon, &req, name) == IPCOM_SUCCESS)
{
const char *cfg;
/**/
ipmip_cli_daemon_iter_request_init(&req, &riter);
while ((cfg = ipmip_cli_config_next(&riter)) != IP_NULL)
ipcom_printf("%s"IP_LF, cfg);
}
ipmip_cli_daemon_request_release(&req);
}
/*
*===========================================================================
* ipmip_cli_context_client_free
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipmip_cli_context_client_free(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_cli_client_t *client)
{
Ipmip_cli_message_t *reply;
Ipcom_list *n;
if (client->request)
ipmip_cli_message_free(ctx, proc, client->request);
if (client->fd != IP_INVALID_SOCKET)
ipcom_socketclose(client->fd);
/* Free any non-processed replies */
while ((reply = IPCOM_LIST_FIRST(&client->replies)) != IP_NULL)
{
ipcom_list_remove(&reply->next);
ipmip_cli_message_free(ctx, proc, reply);
}
while ((n = IPCOM_LIST_FIRST(&client->mcasts)) != IP_NULL)
{
ipcom_list_remove(n);
ipcom_free(n);
}
ipcom_block_delete(&client->block);
ipcom_free(client);
}
IP_STATIC int
ipmip_cli_read_data(Ip_fd fd,
Ipmip_buffer_t *rbuf,
struct Ip_timeval *tv,
Ip_size_t sz)
{
int ret;
if (ipmip_buffer_reserve(rbuf, sz) == IP_FALSE)
return -IP_ERRNO_ENOMEM;
if (tv == IP_NULL)
{
for (; sz > 0;)
{
ret = ipcom_recv(fd, IPMIP_BUFFER_CURRENT(rbuf), sz, 0);
if (ret < 0)
return -ipcom_errno;
else if (ret == 0)
return -IP_ERRNO_ENOTCONN;
/* Append */
ipmip_buffer_append(rbuf, IP_NULL, ret);
sz -= ret;
}
ip_assert(sz == 0);
}
else
{
for (; sz > 0;)
{
Ip_fd_set rset;
/* Clear it */
IP_FD_ZERO(&rset);
/* Add the client socket */
IP_FD_SET(fd, &rset);
ret = ipcom_socketselect(fd + 1, &rset, IP_NULL, IP_NULL, tv);
if (ret == 0)
return sz;
ret = ipcom_recv(fd, IPMIP_BUFFER_CURRENT(rbuf), sz, IP_MSG_DONTWAIT);
if (ret <= 0)
{
if (ret < 0)
{
if (ipcom_errno != IP_ERRNO_EAGAIN && ipcom_errno != IP_ERRNO_EWOULDBLOCK)
return -ipcom_errno;
continue;
}
/* EOF */
return -IP_ERRNO_ENOTCONN;
}
/* Append */
ipmip_buffer_append(rbuf, IP_NULL, ret);
sz -= ret;
}
}
return sz;
}
IP_STATIC int
ipmip_cli_recvmsg(Ip_fd fd,
Ipmip_buffer_t *rbuf,
struct Ip_timeval *tv)
{
struct Ipmip_attr_header *hdr;
Ip_size_t hdr_sz = IPMIP_BUFFER_SIZE(rbuf);
Ip_size_t msg_sz = 0;
int ret = 0;
/* Already have a complete message? */
if (hdr_sz >= IPMIP_ATTR_HDR_LENGTH(0))
{
Ip_u32 sz;
hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(rbuf);
sz = IPMIP_ATTR_HDR_SIZE(hdr);
if (sz == hdr_sz)
{
/* Must Truncate */
ipmip_buffer_shrink(rbuf, 0);
hdr_sz = IPMIP_ATTR_HDR_LENGTH(0);
}
else
{
/* Have some data to read still */
msg_sz = sz - hdr_sz;
hdr_sz = 0;
}
}
else
{
/* Must read header */
hdr_sz = IPMIP_ATTR_HDR_LENGTH(0) - hdr_sz;
}
if (hdr_sz)
{
if ((ret = ipmip_cli_read_data(fd, rbuf, tv, hdr_sz)) != 0)
return ret;
hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(rbuf);
msg_sz = IPMIP_ATTR_HDR_PAYLOAD(hdr);
}
if (msg_sz)
ret = ipmip_cli_read_data(fd, rbuf, tv, msg_sz);
return ret;
}
/*
*===========================================================================
* ipmip_cli_senddata
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipmip_cli_senddata(Ipmip_cli_client_t *client,
Ipmip_cli_message_t *request)
{
for (;;)
{
int remain = IPMIP_BUFFER_SIZE(&request->message) - request->remain;
int rsize = IP_MIN(remain, 1500);
int ret;
if (rsize == 0)
return 0;
rsize = IP_MIN(rsize, 1500);
ret = ipcom_send(client->fd,
ipmip_buffer_offset(&request->message, request->remain),
rsize,
IP_MSG_DONTWAIT);
if (ret < 0)
{
if (ipcom_errno == IP_ERRNO_EAGAIN && ipcom_errno == IP_ERRNO_EWOULDBLOCK)
return remain;
return ret;
}
request->remain += ret;
}
}
/*
*===========================================================================
* ipmip_cli_sendreply
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipmip_cli_sendreply(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_cli_client_t *client,
Ipmip_cli_message_t *request)
{
if(IP_NULL == request)
return;
/* Put it last in the list */
(void)ipcom_block_wait(client->block, -1);
if (IPCOM_LIST_FIRST(&client->replies) == IP_NULL)
{
int ret = ipmip_cli_senddata(client, request);
if (ret == 0)
{
ipcom_block_post(client->block);
ipmip_cli_message_free(ctx, proc, request);
return;
}
}
ipcom_list_insert_last(&client->replies, &request->next);
ipcom_block_post(client->block);
}
/*
*===========================================================================
* ipmip_cli_client_loop
*===========================================================================
* Description:
*
*/
IP_STATIC void
ipmip_cli_client_loop(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_cli_client_t *client)
{
struct Ip_timeval nw;
nw.tv_sec = 0;
nw.tv_usec = 0;
/*********** tick loop ***********/
for (; proc->quit != IP_TRUE;)
{
Ip_fd_set rset;
Ip_fd_set wset;
int ret;
struct Ip_timeval tv;
if (client->request == IP_NULL)
{
client->request = ipmip_cli_message_alloc(&client->ident);
if (client->request == IP_NULL)
return;
}
/* Clear it */
IP_FD_ZERO(&rset);
IP_FD_ZERO(&wset);
(void)ipcom_block_wait(client->block, -1);
/* Add the client socket */
IP_FD_SET(client->fd, &rset);
/**/
if (IPCOM_LIST_FIRST(&client->replies) != IP_NULL)
IP_FD_SET(client->fd, &wset);
ipcom_block_post(client->block);
tv.tv_sec = 0;
tv.tv_usec = 200 * 1000;
ret = ipcom_socketselect(client->fd + 1, &rset, &wset, IP_NULL, &tv);
/* Timeout */
if (ret == 0)
continue;
else if (ret < 0)
{
break;
}
else
{
(void)ipcom_block_wait(client->block, -1);
if (IP_FD_ISSET(client->fd, &wset))
{
Ipmip_cli_message_t *request;
/* Need to send */
while ((request = IPCOM_LIST_FIRST(&client->replies)) != IP_NULL)
{
ret = ipmip_cli_senddata(client, request);
if (ret != 0)
break;
ipcom_list_remove(&request->next);
ipmip_cli_message_free(ctx, proc, request);
}
}
ipcom_block_post(client->block);
if (ret < 0)
break;
if (IP_FD_ISSET(client->fd, &rset))
{
if ((ret = ipmip_cli_recvmsg(client->fd, &client->request->request, &nw)) < 0)
break;
if (ret == 0)
{
struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header*)IPMIP_BUFFER_DATA(&client->request->request);
/**/
if (IPMIP_ATTR_HDR_SYSTEM(hdr) != client->cli->subsystem)
ret = -IP_ERRNO_EINVAL;
else
{
if (ctx->cli->busy)
ret = -IP_ERRNO_EBUSY;
else
{
if (IPMIP_ATTR_HDR_TYPE(hdr) == IPMIP_CLI_TYPE_MULTICAST_ADD || IPMIP_ATTR_HDR_TYPE(hdr) == IPMIP_CLI_TYPE_MULTICAST_DEL)
{
struct Ipmip_attr *attr = IPMIP_ATTR_HDR_DATA(hdr);
Ip_size_t attrlen = IPMIP_ATTR_HDR_PAYLOAD(hdr);
while (IPMIP_ATTR_OK(attr, (int)attrlen))
{
if (IPMIP_ATTR_TYPE(attr) == IPMIP_CLI_MULTICAST_ATTR_CHANNEL && IPMIP_ATTR_PAYLOAD(attr) == sizeof(Ip_u32))
{
Ipmip_cli_client_mcast_t *mc;
Ip_u32 channel = IP_GET_NTOHL(IPMIP_ATTR_DATA(attr));
ipcom_mutex_lock(client->cli->lock);
for (mc = IPCOM_LIST_FIRST(&client->mcasts); mc != IP_NULL; mc = IPCOM_LIST_NEXT(&mc->next))
if (mc->channel == channel)
break;
if (IPMIP_ATTR_HDR_TYPE(hdr) == IPMIP_CLI_TYPE_MULTICAST_ADD)
{
if (mc == IP_NULL)
{
mc = ipcom_calloc(1, sizeof(*mc));
if(IP_NULL == mc)
{
ipcom_mutex_unlock(client->cli->lock);
return;
}
mc->channel = channel;
ipcom_list_insert_last(&client->mcasts, &mc->next);
}
}
else
{
if (mc != IP_NULL)
{
ipcom_list_remove(&mc->next);
ipcom_free(mc);
}
}
ipcom_mutex_unlock(client->cli->lock);
}
attr = IPMIP_ATTR_NEXT(attr, attrlen);
}
/* If we have a reply header; terminate it */
ipmip_attr_hdr_finalize(&client->request->message,
ipmip_attr_hdr_ack_create(&client->request->message,
IPMIP_ATTR_HDR_SYSTEM(hdr),
IPMIP_ATTR_HDR_SEQUENCE(hdr),
IPMIP_ATTR_HDR_TYPE(hdr)));
ipmip_cli_sendreply(ctx, proc, client, client->request);
}
else
{
/* Provide the opaque parameter */
client->request->opaque = client->cli->opaque;
/* Invoke the callback */
ret = (*client->cli->callback) (ctx,
proc,
client->request);
}
}
}
if (ret < 0)
{
/* Reuse the buffer */
ipmip_buffer_assign(&client->request->message, &client->request->request);
/* Clear data */
ipmip_buffer_shrink(&client->request->message, 0);
/* Create the error message */
ipmip_attr_hdr_finalize(&client->request->message,
ipmip_attr_hdr_err_create(&client->request->message,
IPMIP_ATTR_HDR_SYSTEM(hdr),
IPMIP_ATTR_HDR_SEQUENCE(hdr),
IPMIP_ATTR_HDR_TYPE(hdr),
-ret,
ipcom_strerror(-ret)));
/* Send it */
ipmip_cli_sendreply(ctx, proc, client, client->request);
}
/* No longer ours */
client->request = IP_NULL;
}
}
}
}
}
/*
*===========================================================================
* ipmip_cli_start_client
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip_cli_start_client(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_cli_context_t *cli,
Ip_fd fd,
Ipmip_cli_ident_t *ident)
{
/* Do create a new client */
Ipmip_cli_client_t *client = ipcom_calloc(1, sizeof(*client));
if (client)
{
Ip_socklen_t slen;
ipcom_block_create(&client->block);
ipcom_mutex_lock(cli->lock);
client->ident.pid = ++cli->pids;
ipcom_mutex_unlock(cli->lock);
client->ident.timestamp = ipmip_util_time();
client->cli = cli;
client->fd = fd;
ipcom_list_init(&client->replies);
ipcom_list_init(&client->mcasts);
if (ident)
*ident = client->ident;
/* Connection information */
slen = sizeof(client->conn_local);
(void)ipcom_getsockname(fd, &client->conn_local.sa, &slen);
slen = sizeof(client->conn_remote);
(void)ipcom_getpeername(fd, &client->conn_remote.sa, &slen);
client->proc = ipmip_proc_start(ctx,
proc,
"cli_client",
(Ipmip_proc_func_t)ipmip_cli_client_loop,
client);
if (client->proc == IP_NULL)
{
ipmip_cli_context_client_free(ctx, proc, client);
return IP_FALSE;
}
ipcom_mutex_lock(cli->lock);
ipcom_list_insert_first(&cli->clients, &client->next);
ipcom_mutex_unlock(cli->lock);
/* Release it */
ipcom_block_post(client->block);
return IP_TRUE;
}
return IP_FALSE;
}
/*
*===========================================================================
* ipmip_cli_loop
*===========================================================================
* Description:
*
*/
IP_STATIC void
ipmip_cli_loop(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_cli_context_t *cli)
{
Ipmip_cli_client_t *client;
int opt;
Ip_socklen_t slen;
union Ip_sockaddr_union saX;
cli->sfd = IP_INVALID_SOCKET;
/* Create the FD */
#ifdef IPCOM_USE_INET6
if (cli->sin6.sin6_family == IP_AF_INET6)
{
cli->sfd = ipcom_socket(IP_AF_INET6, IP_SOCK_STREAM, IP_IPPROTO_TCP);
if (cli->sfd != IP_INVALID_SOCKET)
{
opt = 1;
(void)ipcom_setsockopt(cli->sfd, IP_SOL_SOCKET, IP_SO_REUSEPORT, (char *)&opt, sizeof(opt));
slen = IPCOM_SA_LEN_GET(&cli->sin6);
if (ipcom_bind(cli->sfd, (struct Ip_sockaddr *) &cli->sin6, slen) >= 0)
goto cli_process;
ipcom_socketclose(cli->sfd);
cli->sfd = IP_INVALID_SOCKET;
}
}
#endif
#ifdef IPCOM_USE_INET
if (cli->sin4.sin_family == IP_AF_INET)
{
cli->sfd = ipcom_socket(IP_AF_INET, IP_SOCK_STREAM, IP_IPPROTO_TCP);
if (cli->sfd != IP_INVALID_SOCKET)
{
opt = 1;
(void)ipcom_setsockopt(cli->sfd, IP_SOL_SOCKET, IP_SO_REUSEPORT, (char *)&opt, sizeof(opt));
slen = IPCOM_SA_LEN_GET(&cli->sin4);
if (ipcom_bind(cli->sfd, (struct Ip_sockaddr *) &cli->sin4, slen) >= 0)
goto cli_process;
ipcom_socketclose(cli->sfd);
cli->sfd = IP_INVALID_SOCKET;
}
}
#endif
cli_process:
if (cli->sfd == IP_INVALID_SOCKET)
goto errout;
slen = sizeof(saX);
if (ipcom_getsockname(cli->sfd, (struct Ip_sockaddr *)&saX, &slen) < 0)
goto errout;
else
{
Ip_u16 port = 0;
#ifdef IPCOM_USE_INET6
if (saX.sa.sa_family == IP_AF_INET6)
port = saX.sin6.sin6_port;
#endif
#ifdef IPCOM_USE_INET
if (saX.sa.sa_family == IP_AF_INET)
port = saX.sin.sin_port;
#endif
/* Write connection information */
ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf), "%s %u", ipmip_ntop_sa(proc, &saX), ipcom_ntohs(port));
ipmip_sysvar_set(proc->ntop.ntop_pbuf, "ipmip.cli.%s", cli->header);
}
if (ipcom_listen(cli->sfd, 5) < 0)
goto errout;
/*********** tick loop ***********/
for (; proc->quit != IP_TRUE;)
{
Ip_fd_set rset;
int ret;
struct Ip_timeval tv;
Ipmip_cli_client_t *lclient;
/* Try collect clients */
ipcom_mutex_lock(cli->lock);
for (client = IPCOM_LIST_FIRST(&cli->clients); client != IP_NULL;)
{
lclient = IPCOM_LIST_NEXT(&client->next);
if (ipmip_proc_collect(ctx,proc,client->proc))
{
ipcom_list_remove(&client->next);
ipmip_cli_context_client_free(ctx, proc, client);
}
client = lclient;
}
ipcom_mutex_unlock(cli->lock);
/* Clear it */
IP_FD_ZERO(&rset);
/* Add the client socket */
IP_FD_SET(cli->sfd, &rset);
tv.tv_sec = 0;
tv.tv_usec = 200 * 1000;
ret = ipcom_socketselect(cli->sfd + 1, &rset, IP_NULL, IP_NULL, &tv);
/* Timeout */
if (ret == 0)
continue;
else if (ret > 0)
{
slen = sizeof(saX);
/* Check the */
if (IP_FD_ISSET(cli->sfd, &rset))
{
Ip_fd cfd = ipcom_accept(cli->sfd, (struct Ip_sockaddr *)&saX, &slen);
if (cfd != IP_INVALID_SOCKET)
{
if (!ipmip_cli_start_client(ctx, proc, ctx->cli, cfd, IP_NULL))
ipcom_socketclose(cfd);
}
}
}
}
errout:
/* Stop all clients */
for (client = IPCOM_LIST_FIRST(&cli->clients); client != IP_NULL; client = IPCOM_LIST_NEXT(&client->next))
ipmip_proc_stop(ctx, proc, client->proc, IP_NULL, IP_NULL);
/* Destroy all clients */
ipcom_mutex_lock(cli->lock);
while ((client = IPCOM_LIST_FIRST(&cli->clients)) != IP_NULL)
{
ipcom_list_remove(&client->next);
ipmip_cli_context_client_free(ctx, proc, client);
}
ipcom_mutex_unlock(cli->lock);
if (cli->sfd != IP_INVALID_SOCKET)
ipcom_socketclose(cli->sfd);
}
IP_STATIC Ipmip_cli_message_t *
ipmip_cli_message_duplicate(Ipmip_cli_message_t *request)
{
Ipmip_cli_message_t *msg = ipmip_cli_message_alloc(&request->ident);
if(IP_NULL == msg)
{
return IP_NULL;
}
/**/
ipmip_buffer_append(&msg->message, IPMIP_BUFFER_DATA(&request->message), IPMIP_BUFFER_SIZE(&request->message));
return msg;
}
/*
*===========================================================================
* ipmip_cli_connect
*===========================================================================
* Description: Connect to a CLI context
* Parameters: proc - Process context
* header - The ipmip name
* magic - Magic
* version - Version
* Returns: A connection context if successful
*
*/
IP_STATIC Ip_fd
ipmip_cli_connect(Ipmip_proc_t *proc,
union Ip_sockaddr_union *remote,
union Ip_sockaddr_union *local)
{
Ip_fd fd = IP_INVALID_SOCKET;
IPMIP_UNUSED_PARAMETER(proc);
if (local != IP_NULL && local->sa.sa_family != remote->sa.sa_family)
return IP_INVALID_SOCKET;
fd = ipcom_socket(remote->sa.sa_family, IP_SOCK_STREAM, IP_IPPROTO_TCP);
if (fd == IP_INVALID_SOCKET)
return fd;
if (local)
{
int opt = 1;
Ip_socklen_t slen;
(void)ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_REUSEPORT, (char *)&opt, sizeof(opt));
slen = IPCOM_SA_LEN_GET(&local->sa);
if (ipcom_bind(fd, (struct Ip_sockaddr *) &local->sa, slen) < 0)
{
ipcom_socketclose(fd);
return IP_INVALID_SOCKET;
}
}
if (ipcom_connect(fd, &remote->sa, IPCOM_SA_LEN_GET(&remote->sa)) != 0)
{
ipcom_socketclose(fd);
fd = IP_INVALID_SOCKET;
}
return fd;
}
/*
*===========================================================================
* ipmip_cli_connect
*===========================================================================
* Description: Connect to a CLI context
* Parameters: proc - Process context
* header - The ipmip name
* magic - Magic
* version - Version
* Returns: A connection context if successful
*
*/
IP_STATIC Ip_fd
ipmip_cli_connect_local(Ipmip_proc_t *proc,
const char *header)
{
Ip_fd fd = IP_INVALID_SOCKET;
char *pvar;
union Ip_sockaddr_union saX;
IPMIP_UNUSED_PARAMETER(proc);
pvar = ipmip_sysvar("ipmip.cli.%s", header);
if (pvar == IP_NULL)
return fd;
if (!ipmip_util_sockaddrX(pvar, &saX))
{
ipcom_free(pvar);
return fd;
}
ipcom_free(pvar);
/* Connect */
return ipmip_cli_connect(proc, &saX, IP_NULL);
}
IP_STATIC int
ipmip_cli_daemon_request_reply(Ipmip_cli_daemon_t *daemon_info,
Ipmip_cli_daemon_req_t *daemon_req)
{
struct Ipmip_attr_header *req_hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&daemon_req->reqbuf);
for (;;)
{
struct Ipmip_attr_header *hdr;
int ret = ipmip_cli_daemon_recvmsg(daemon_info, IP_NULL);
/* */
if (ret < 0)
return ret;
hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&daemon_info->message);
if (IPMIP_ATTR_HDR_SYSTEM(hdr) != IPMIP_ATTR_HDR_SYSTEM(req_hdr) || IPMIP_ATTR_HDR_SEQUENCE(hdr) != IPMIP_ATTR_HDR_SEQUENCE(req_hdr))
{
IPCOM_LOG4(ERR, "BAD: %08x != %08x, %08x != %08x",
IPMIP_ATTR_HDR_SYSTEM(hdr),
IPMIP_ATTR_HDR_SYSTEM(req_hdr),
IPMIP_ATTR_HDR_SEQUENCE(hdr),
IPMIP_ATTR_HDR_SEQUENCE(req_hdr));
continue;
}
if (IPMIP_ATTR_HDR_TYPE(hdr) != IPMIP_ATTR_HDR_TYPE(req_hdr))
return -IP_ERRNO_EINVAL;
if (IPMIP_ATTR_HDR_ERROR(hdr) != 0)
return -IPMIP_ATTR_HDR_ERROR(hdr);
/* Copy reply to request */
if (IP_BIT_ISFALSE(daemon_req->reqflags, IPMIP_CLI_REQ_REPLY_NOCOPY))
{
ipmip_buffer_shrink(&daemon_req->reqbuf, 0);
ipmip_buffer_append(&daemon_req->reqbuf, IPMIP_BUFFER_DATA(&daemon_info->message), IPMIP_BUFFER_SIZE(&daemon_info->message));
}
return 0;
}
}
/*
*===========================================================================
* ipmip_cli_context_stop
*===========================================================================
* Description: Stop the CLI context
* Parameters: ctx - Context
* proc - Process
* Returns:
*
*/
IP_STATIC void
ipmip_cli_context_kill(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_cli_context_t *cli)
{
/* Lock the global mutex */
if (cli != IP_NULL && cli->proc != IP_NULL)
{
cli->busy = IP_TRUE;
ipmip_proc_stop(ctx,
proc,
cli->proc,
IP_NULL,
IP_NULL);
cli->proc = IP_NULL;
}
}
/*
*===========================================================================
* ipmip_cli_context_start
*===========================================================================
* Description: Start the CLI context
* Parameters: ctx - Context
* proc - Process
* Returns: IP_TRUE on success.
*
*/
IP_STATIC Ip_bool
ipmip_cli_context_exec(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_cli_context_t *cli)
{
/* Lock the global mutex */
if (cli != IP_NULL && cli->proc == IP_NULL)
{
cli->proc = ipmip_proc_start(ctx,
proc,
"cli",
(Ipmip_proc_func_t) ipmip_cli_loop,
cli);
if (cli->proc != IP_NULL)
cli->busy = IP_FALSE;
}
return cli != IP_NULL && cli->proc != IP_NULL;
}
IP_STATIC void
ipmip_cli_context_free(struct Ipmip_proc *proc,
Ipmip_cli_context_t *cli)
{
IPMIP_UNUSED_PARAMETER(proc);
if (cli != IP_NULL)
{
ipcom_free(cli->header);
ipcom_mutex_delete(&cli->lock);
ipcom_free(cli);
}
}
/*
*===========================================================================
* ipmip_cli_context_create
*===========================================================================
* Description: Allocate an CLI context
* Parameters: ctx - Context
* proc - Process
* header - The ipmip name
* magic - Magic
* version - Version
* callback - Function callback to be invoked on messages
* Returns: IP_TRUE on success
*
*/
IP_STATIC Ipmip_cli_context_t *
ipmip_cli_context_alloc(struct Ipmip_proc *proc,
const char *header,
Ip_u32 subsystem,
Ipmip_cli_callback_t callback,
union Ip_sockaddr_union *saX,
void *opaque)
{
Ipmip_cli_context_t *cli = ipcom_calloc(1, sizeof(*cli));
IPMIP_UNUSED_PARAMETER(proc);
if (cli)
{
cli->callback = callback;
cli->subsystem = subsystem;
cli->header = ipcom_strdup(header);
cli->opaque = opaque;
if (cli->header == IP_NULL)
goto errout;
if (saX == IP_NULL)
{
#ifdef IPCOM_USE_INET6
cli->sin6.sin6_family = IP_AF_INET6;
IPCOM_SA_LEN_SET(&cli->sin6, sizeof(cli->sin6));
ipcom_memcpy(&cli->sin6.sin6_addr, &ip_in6addr_loopback, sizeof(ip_in6addr_loopback));
cli->sin6.sin6_port = 0;
#endif
#ifdef IPCOM_USE_INET
cli->sin4.sin_family = IP_AF_INET;
IPCOM_SA_LEN_SET(&cli->sin4, sizeof(cli->sin4));
cli->sin4.sin_addr.s_addr = ip_htonl(IP_INADDR_LOOPBACK);
cli->sin4.sin_port = 0;
#endif
}
else
{
#ifdef IPCOM_USE_INET6
if (saX->sa.sa_family == IP_AF_INET6)
ipcom_memcpy(&cli->sin6, &saX->sin6, sizeof(cli->sin6));
#endif
#ifdef IPCOM_USE_INET
if (saX->sa.sa_family == IP_AF_INET)
ipcom_memcpy(&cli->sin4, &saX->sin, sizeof(cli->sin4));
#endif
}
(void)ipcom_mutex_create(&cli->lock);
/* Create the client head */
ipcom_list_init(&cli->clients);
return cli;
}
errout:
ipcom_free(cli);
return IP_NULL;
}
/*
*===========================================================================
* ipmip_cli_sendbuffer
*===========================================================================
* Description: Send a message over fd
* Parameters: fd - File descriptor.
* buf - Pointer to buffer.
* Returns: 0 if successful.
*
*/
IP_STATIC int
ipmip_cli_sendbuffer(Ip_fd fd,
Ipmip_buffer_t *buf)
{
if (buf && buf->offset)
{
Ip_size_t totsize = IPMIP_BUFFER_SIZE(buf);
Ip_size_t csize = 0;
Ip_u8 *data = IPMIP_BUFFER_PTR(buf);
while (csize != totsize)
{
Ip_size_t ssize = IP_MIN((totsize - csize), 1500);
if (ipcom_send(fd, (void *)&data[csize], ssize, 0) != (int)ssize)
return -ipcom_errno;
csize += ssize;
}
return IPCOM_SUCCESS;
}
return -IP_ERRNO_EINVAL;
}
/*
*===========================================================================
* ipmip_cli_command
*===========================================================================
* Description: Issue a command and retrieve the reply
* Parameters: fd - File descriptor.
* rbuf - Pointer to buffer pointer. Will hold the
* dynamically allocated buffer on success.
* Returns: IP_TRUE on success
*
*/
IP_STATIC void
ipmip_cli_request_setup(Ipmip_buffer_t *rbuf,
Ip_u32 type,
Ip_u32 subsystem,
Ip_u32 seq)
{
/**/
Ip_size_t off = IPMIP_BUFFER_SIZE(rbuf);
if (off)
{
Ipmip_buffer_t nbuf;
Ip_size_t rhdr;
ipmip_buffer_init(&nbuf);
rhdr = ipmip_attr_hdr_req_create(&nbuf,subsystem,seq,type);
ipmip_buffer_append(&nbuf, IPMIP_BUFFER_DATA(rbuf), off);
ipmip_attr_hdr_finalize(&nbuf, rhdr);
ipmip_buffer_assign(rbuf, &nbuf);
}
else
{
ipmip_attr_hdr_finalize(rbuf,
ipmip_attr_hdr_req_create(rbuf,subsystem,seq,type));
}
}
/*
*===========================================================================
* ipmip_cli_daemon_request
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipmip_cli_daemon_request_send(Ipmip_cli_daemon_t *daemon_info,
Ipmip_cli_daemon_req_t *daemon_req)
{
int i;
/**/
ipmip_cli_request_setup(&daemon_req->reqbuf, daemon_req->reqtype, daemon_info->pid, ++daemon_info->seq);
for (i = 0; i < 10; i++)
{
int ret = -IP_ERRNO_ENOTCONN;
if (daemon_info->fd == IP_INVALID_SOCKET)
{
if (!ipmip_cli_daemon_connect(daemon_info))
{
ipcom_sleep(1);
continue;
}
}
ret = ipmip_cli_sendbuffer(daemon_info->fd, &daemon_req->reqbuf);
switch (-ret)
{
default:
case IPCOM_SUCCESS:
return ret;
case IP_ERRNO_ECONNRESET:
case IP_ERRNO_ENOTCONN:
case IP_ERRNO_EBUSY:
ipmip_cli_daemon_disconnect(daemon_info);
break;
}
}
/**/
return -IP_ERRNO_ENOTCONN;
}
/*
*===========================================================================
* ipmip_cli_message_commit
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip_cli_message_deliver(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_cli_context_t *cli,
Ipmip_cli_message_t *request)
{
Ipmip_cli_client_t *client;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
if (cli == IP_NULL)
cli = ctx->cli;
/* Try collect clients */
ipcom_mutex_lock(cli->lock);
for (client = IPCOM_LIST_FIRST(&cli->clients); client != IP_NULL; client = IPCOM_LIST_NEXT(&client->next))
{
if (client->ident.pid == request->ident.pid && client->ident.timestamp == request->ident.timestamp)
{
/* Found it */
ipmip_cli_sendreply(ctx, proc, client, request);
request = IP_NULL;
break;
}
}
ipcom_mutex_unlock(cli->lock);
if (request)
return IP_FALSE;
return IP_TRUE;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL void
ipmip_cli_message_multicast(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_cli_context_t *cli,
Ip_u32 channel,
Ipmip_cli_message_t *request)
{
Ipmip_cli_client_t *client;
Ipmip_cli_client_t *nclient = IP_NULL;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
/**/
if (cli == IP_NULL)
cli = ctx->cli;
/* Try collect clients */
ipcom_mutex_lock(cli->lock);
for (client = IPCOM_LIST_FIRST(&cli->clients); client != IP_NULL; client = IPCOM_LIST_NEXT(&client->next))
{
Ipmip_cli_client_mcast_t *mc;
for (mc = IPCOM_LIST_FIRST(&client->mcasts); mc != IP_NULL; mc = IPCOM_LIST_NEXT(&mc->next))
if (mc->channel == channel)
break;
if (mc != IP_NULL)
{
if (nclient)
ipmip_cli_sendreply(ctx, proc, nclient, ipmip_cli_message_duplicate(request));
nclient = client;
}
}
if (nclient)
{
ipmip_cli_sendreply(ctx, proc, nclient, request);
request = IP_NULL;
}
ipcom_mutex_unlock(cli->lock);
if (request)
ipmip_cli_message_free(ctx, proc, request);
}
/*
*===========================================================================
* ipmip_cli_context_create
*===========================================================================
* Description: Allocate an CLI context
* Parameters: ctx - Context
* proc - Process
* header - The ipmip name
* magic - Magic
* version - Version
* callback - Function callback to be invoked on messages
* Returns: IP_TRUE on success
*
*/
IP_GLOBAL Ip_bool
ipmip_cli_context_create(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
const char *header,
Ip_u32 subsystem,
Ipmip_cli_callback_t callback)
{
Ipmip_cli_context_t *cli = ipmip_cli_context_alloc(proc, header, subsystem, callback, IP_NULL, IP_NULL);
if (cli)
{
ctx->cli = cli;
return IP_TRUE;
}
return IP_FALSE;
}
/*
*===========================================================================
* ipmip_cli_context_start
*===========================================================================
* Description: Start the CLI context
* Parameters: ctx - Context
* proc - Process
* Returns: IP_TRUE on success.
*
*/
IP_GLOBAL Ip_bool
ipmip_cli_context_start(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
/**/
return ipmip_cli_context_exec(ctx, proc, ctx->cli);
}
/*
*===========================================================================
* ipmip_cli_context_stop
*===========================================================================
* Description: Stop the CLI context
* Parameters: ctx - Context
* proc - Process
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_context_stop(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
ipmip_cli_context_kill(ctx, proc, ctx->cli);
}
/*
*===========================================================================
* ipmip_cli_context_destroy
*===========================================================================
* Description: Free an CLI context
* Parameters: ctx - Context
* proc - Process
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_context_destroy(struct Ipmip_context *ctx,
struct Ipmip_proc *proc)
{
ipmip_cli_context_free(proc, ctx->cli);
ctx->cli = IP_NULL;
}
/*
*===========================================================================
* ipmip_cli_message_commit
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_message_commit(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_cli_message_t *request)
{
/**/
if (!ipmip_cli_message_deliver(ctx, proc, ctx->cli, request))
ipmip_cli_message_free(ctx, proc, request);
}
/*
*===========================================================================
* ipmip_cli_message_free
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_message_free(struct Ipmip_context *ctx,
struct Ipmip_proc *proc,
Ipmip_cli_message_t *req)
{
ipmip_timer_cancel(ctx, proc, &req->timer);
ipmip_buffer_release(&req->message);
ipmip_buffer_release(&req->request);
ipcom_free(req);
}
/*
*===========================================================================
* ipmip_cli_message_alloc
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ipmip_cli_message_t *
ipmip_cli_message_alloc(Ipmip_cli_ident_t *ident)
{
Ipmip_cli_message_t *req = ipcom_calloc(1, sizeof(*req));
if(IP_NULL == req)
{
return IP_NULL;
}
ipmip_buffer_init(&req->request);
ipmip_buffer_init(&req->message);
IPMIP_TIMER_INIT(&req->timer);
/**/
if (ident)
req->ident = *ident;
return req;
}
/*
*===========================================================================
* ipmip_cli_daemon_connect
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_bool
ipmip_cli_daemon_connect(Ipmip_cli_daemon_t *daemon_info)
{
if (daemon_info->fd == IP_INVALID_SOCKET)
{
daemon_info->seq = ((Ip_u32)ipmip_util_time()) + ipcom_random();;
daemon_info->fd = ipmip_cli_connect_local(IP_NULL, daemon_info->header);
ipmip_buffer_init(&daemon_info->message);
}
return daemon_info->fd != IP_INVALID_SOCKET;
}
/*
*===========================================================================
* ipmip_cli_daemon_disconnect
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_daemon_disconnect(Ipmip_cli_daemon_t *daemon_info)
{
if (daemon_info->fd != IP_INVALID_SOCKET)
{
ipcom_socketclose(daemon_info->fd);
daemon_info->fd = IP_INVALID_SOCKET;
ipmip_buffer_release(&daemon_info->message);
}
}
/*
*===========================================================================
* ipmip_cli_daemon_init
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_daemon_init(Ipmip_cli_daemon_t *daemon_info,
const char *header,
Ip_u32 pid)
{
daemon_info->fd = IP_INVALID_SOCKET;
daemon_info->header = header;
daemon_info->pid = pid;
}
IP_GLOBAL int
ipmip_cli_daemon_recvmsg(Ipmip_cli_daemon_t *daemon_info,
struct Ip_timeval *tv)
{
/**/
return ipmip_cli_recvmsg(daemon_info->fd, &daemon_info->message, tv);
}
/*
*===========================================================================
* ipmip_cli_daemon_request
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL int
ipmip_cli_daemon_request(Ipmip_cli_daemon_t *daemon_info,
Ipmip_cli_daemon_req_t *daemon_req)
{
int ret = ipmip_cli_daemon_request_send(daemon_info, daemon_req);
if (ret == IPCOM_SUCCESS)
ret = ipmip_cli_daemon_request_reply(daemon_info, daemon_req);
return ret;
}
/*
*===========================================================================
* ipmip_cli_daemon_request_init
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_daemon_request_init(Ipmip_cli_daemon_req_t *daemon_req)
{
daemon_req->reqflags = 0;
ipmip_buffer_init(&daemon_req->reqbuf);
}
/*
*===========================================================================
* ipmip_cli_daemon_request_start
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_daemon_request_start(Ipmip_cli_daemon_req_t *daemon_req,
Ip_u32 req_type)
{
ipmip_buffer_shrink(&daemon_req->reqbuf, 0);
daemon_req->reqtype = req_type;
}
/*
*===========================================================================
* ipmip_cli_daemon_request_release
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip_cli_daemon_request_release(Ipmip_cli_daemon_req_t *daemon_req)
{
ipmip_buffer_release(&daemon_req->reqbuf);
}
/*
*===========================================================================
* ipmip_cli_event_next
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_bool
ipmip_cli_event_next(Ipmip_attr_iter_t *iter,
const char **message,
Ip_time_t *tval,
int *loglevel)
{
/**/
struct Ipmip_attr *rta = ipmip_attr_iter_next(iter, IPMIP_CLI_ITEM_EVENT);
if (rta != IP_NULL)
{
struct Ipmip_attr *eattr[IPMIP_CLI_ITEM_EVENT_MAX];
/* parse it */
ipmip_attr_parse(IPMIP_CLI_ITEM_EVENT_MAX,
IPMIP_ATTR_DATA(rta),
IPMIP_ATTR_PAYLOAD(rta),
eattr);
if (eattr[IPMIP_CLI_ITEM_EVENT_TIME] &&
eattr[IPMIP_CLI_ITEM_EVENT_MESSAGE] &&
eattr[IPMIP_CLI_ITEM_EVENT_LEVEL])
{
*loglevel = (int)ipmip_attr_get_u32(eattr[IPMIP_CLI_ITEM_EVENT_LEVEL]);
*tval = ipmip_attr_get_time_t(eattr[IPMIP_CLI_ITEM_EVENT_TIME]);
*message = ipmip_attr_get_str(eattr[IPMIP_CLI_ITEM_EVENT_MESSAGE]);
return IP_TRUE;
}
}
return IP_FALSE;
}
IP_PUBLIC int
ipmip_cli_event_list(Ipmip_cli_daemon_t *daemon,
Ipmip_cli_daemon_req_t *req)
{
ipmip_cli_daemon_request_start(req, IPMIP_CLI_EVENT_GET);
return ipmip_cli_daemon_request(daemon, req);
}
IP_PUBLIC int
ipmip_cli_event_flush(Ipmip_cli_daemon_t *daemon)
{
Ipmip_cli_daemon_req_t req;
int rval;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_EVENT_FLUSH);
rval = ipmip_cli_daemon_request(daemon, &req);
ipmip_cli_daemon_request_release(&req);
return rval;
}
IP_PUBLIC void
ipmip_cli_event_print(Ipmip_proc_t *proc,
Ipmip_cli_daemon_t *daemon,
int loglevel)
{
Ipmip_cli_daemon_req_t req;
ipmip_cli_daemon_request_init(&req);
if (ipmip_cli_event_list(daemon, &req) == IPCOM_SUCCESS)
{
Ipmip_attr_iter_t riter;
const char *msg;
Ip_time_t tm;
int ll;
/**/
ipmip_cli_daemon_iter_request_init(&req, &riter);
while (ipmip_cli_event_next(&riter, &msg, &tm, &ll))
{
if (loglevel < 0 || ll <= loglevel)
{
/* Time, subject & message */
ipcom_printf("%s %s: %s"IP_LF,
ipmip_ntop_tm(proc, tm),
ipmip_util_syslog_priority_name(ll),
msg);
}
}
}
ipmip_cli_daemon_request_release(&req);
}
IP_PUBLIC const char *
ipmip_cli_config_next(Ipmip_attr_iter_t *iter)
{
/**/
return ipmip_attr_get_str(ipmip_attr_iter_next(iter, IPMIP_CLI_ITEM_CONFIG_LINE));
}
IP_PUBLIC const char *
ipmip_cli_name_next(Ipmip_attr_iter_t *iter)
{
/**/
return ipmip_attr_get_str(ipmip_attr_iter_next(iter, IPMIP_CLI_ITEM_NAME));
}
IP_PUBLIC int
ipmip_cli_name_list(Ipmip_cli_daemon_t *daemon,
Ipmip_cli_daemon_req_t *req)
{
ipmip_cli_daemon_request_start(req, IPMIP_CLI_NAME_LIST);
return ipmip_cli_daemon_request(daemon, req);
}
IP_PUBLIC void
ipmip_cli_set_name(Ipmip_cli_daemon_req_t *req,
const char *name)
{
if (name)
ipmip_attr_put_str(&req->reqbuf, IPMIP_CLI_ITEM_NAME, name);
}
IP_PUBLIC void
ipmip_cli_set_size(Ipmip_cli_daemon_req_t *req,
Ip_u32 size)
{
ipmip_attr_put_u32(&req->reqbuf, IPMIP_CLI_ITEM_SIZE, size);
}
IP_PUBLIC int
ipmip_cli_config_list(Ipmip_cli_daemon_t *daemon,
Ipmip_cli_daemon_req_t *req,
const char *name)
{
ipmip_cli_daemon_request_start(req, IPMIP_CLI_CONFIG_GET);
ipmip_cli_set_name(req, name);
return ipmip_cli_daemon_request(daemon, req);
}
IP_PUBLIC void
ipmip_cli_config_print(Ipmip_proc_t *proc,
Ipmip_cli_daemon_t *daemon,
const char *name)
{
IPMIP_UNUSED_PARAMETER(proc);
if (name == IP_NULL)
{
Ipmip_cli_daemon_req_t nreq;
ipmip_cli_daemon_request_init(&nreq);
/**/
if (ipmip_cli_name_list(daemon, &nreq) == IPCOM_SUCCESS)
{
Ipmip_attr_iter_t niter;
ipmip_cli_daemon_iter_request_init(&nreq, &niter);
while ((name = ipmip_cli_name_next(&niter)) != IP_NULL)
ipmip_cli_config_name_print(proc, daemon, name);
return;
}
ipmip_cli_daemon_request_release(&nreq);
}
ipmip_cli_config_name_print(proc, daemon, name);
}
IP_GLOBAL void
ipmip_cli_config_printf(struct Ipmip_buffer *reqbuf,
const char *format,
...)
{
Ip_size_t off;
va_list ap;
if (ipmip_buffer_reserve(reqbuf, 256))
{
struct Ipmip_attr *attr;
int sz;
off = ipmip_attr_begin(reqbuf, IPMIP_CLI_ITEM_CONFIG_LINE);
/* Get */
attr = ipmip_buffer_offset(reqbuf, off);
va_start(ap, format);
sz = ipcom_vsnprintf(IPMIP_ATTR_DATA(attr), 256 - IPMIP_ATTR_LENGTH(0), format , ap);
va_end(ap);
/* Move past */
ipmip_buffer_append(reqbuf, IP_NULL, sz + 1);
/* Terminate */
ipmip_attr_end(reqbuf, off);
}
}
IP_PUBLIC void
ipmip_cli_loglevel_set(Ipmip_cli_daemon_t *daemon,
int loglevel)
{
Ipmip_cli_daemon_req_t req;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_LOG_LEVEL_SET);
ipmip_cli_set_size(&req, (Ip_u32)loglevel);
ipmip_cli_daemon_request(daemon, &req);
ipmip_cli_daemon_request_release(&req);
}
IP_PUBLIC void
ipmip_cli_multicast_add(Ipmip_cli_daemon_t *daemon,
Ip_u32 channel)
{
Ipmip_cli_daemon_req_t req;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_TYPE_MULTICAST_ADD);
ipmip_attr_put_u32(&req.reqbuf, IPMIP_CLI_MULTICAST_ATTR_CHANNEL, channel);
ipmip_cli_daemon_request(daemon, &req);
ipmip_cli_daemon_request_release(&req);
}
IP_PUBLIC void
ipmip_cli_multicast_del(Ipmip_cli_daemon_t *daemon,
Ip_u32 channel)
{
Ipmip_cli_daemon_req_t req;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_TYPE_MULTICAST_DEL);
ipmip_attr_put_u32(&req.reqbuf, IPMIP_CLI_MULTICAST_ATTR_CHANNEL, channel);
ipmip_cli_daemon_request(daemon, &req);
ipmip_cli_daemon_request_release(&req);
}
IP_PUBLIC void
ipmip_cli_history_set(Ipmip_cli_daemon_t *daemon,
Ip_u32 history)
{
Ipmip_cli_daemon_req_t req;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_EVENT_HISTORY_SET);
ipmip_cli_set_size(&req, history);
ipmip_cli_daemon_request(daemon, &req);
ipmip_cli_daemon_request_release(&req);
}
IP_PUBLIC Ip_u32
ipmip_cli_loglevel_get(Ipmip_cli_daemon_t *daemon)
{
Ipmip_cli_daemon_req_t req;
Ip_u32 size = 0;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_LOG_LEVEL_GET);
if (ipmip_cli_daemon_request(daemon, &req) == IPCOM_SUCCESS)
size = ipmip_attr_hdr_find_u32(ipmip_cli_daemon_request_header(&req), IPMIP_CLI_ITEM_SIZE);
ipmip_cli_daemon_request_release(&req);
return size;
}
IP_PUBLIC Ip_u32
ipmip_cli_history_get(Ipmip_cli_daemon_t *daemon)
{
Ipmip_cli_daemon_req_t req;
Ip_u32 size = 0;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_EVENT_HISTORY_GET);
if (ipmip_cli_daemon_request(daemon, &req) == IPCOM_SUCCESS)
size = ipmip_attr_hdr_find_u32(ipmip_cli_daemon_request_header(&req), IPMIP_CLI_ITEM_SIZE);
ipmip_cli_daemon_request_release(&req);
return size;
}
IP_GLOBAL int
ipmip_cli_shell_cmd(int argc,
char **argv,
Ipmip_proc_t *proc,
Ipmip_cli_daemon_t *daemon)
{
static Ipcom_cmd_int_str_map ops[] = {
{ 0, "loglevel" },
{ 1, "history" },
{ 2, "config" },
{ 3, "events" },
{ 4, "debug" },
{ 0, 0 }
};
static Ipcom_cmd_int_str_map set_get_ops[] = {
{ 0, "set" },
{ 1, "get" },
{ 0, 0 }
};
static Ipcom_cmd_int_str_map events_ops[] = {
{ 0, "get" },
{ 1, "flush" },
{ 0, 0 }
};
Ipcom_getopt opt;
Ipmip_cli_daemon_req_t req;
int op_val;
int i;
const char *name = IP_NULL;
ipmip_cli_daemon_request_init(&req);
if (argc < 2)
return -1;
op_val = ipcom_cmd_str_to_key(ops, argv[1]);
if (op_val == -1)
return -1;
ipmip_cli_daemon_request_init(&req);
ipcom_getopt_clear_r(&opt);
if (op_val == 0)
{
/* LOGLEVEL */
int sg;
int val;
if (argc < 3)
{
ipcom_printf("Too few arguments to loglevel command"IP_LF);
goto exit_out;
}
sg = ipcom_cmd_str_to_key(set_get_ops, argv[2]);
if (sg == -1)
{
ipcom_printf("Unknown loglevel subcommand %s"IP_LF, argv[2]);
goto exit_out;
}
if (sg == 0)
{
/* SET */
if (argc < 4)
{
ipcom_printf("Too few arguments to loglevel set command"IP_LF);
goto exit_out;
}
if ((val = ipmip_util_syslog_priority(argv[3])) == -1)
{
ipcom_printf("Bad priority value %s in loglevel set command"IP_LF, argv[3]);
goto exit_out;
}
ipmip_cli_loglevel_set(daemon, val);
}
/* GET */
val = ipmip_cli_loglevel_get(daemon);
ipcom_printf("Current Loglevel: %s"IP_LF, ipmip_util_syslog_priority_name(val));
}
else if (op_val == 1)
{
/* HISTORY */
int sg;
Ip_u32 val;
if (argc < 3)
{
ipcom_printf("Too few arguments to history command"IP_LF);
goto exit_out;
}
sg = ipcom_cmd_str_to_key(set_get_ops, argv[2]);
if (sg == -1)
{
ipcom_printf("Unknown history subcommand %s"IP_LF, argv[2]);
goto exit_out;
}
if (sg == 0)
{
/* SET */
if (argc < 4)
{
ipcom_printf("Too few arguments to history set command"IP_LF);
goto exit_out;
}
val = ipcom_strtoul(argv[3], IP_NULL, 0);
ipmip_cli_history_set(daemon, val);
}
/* GET */
val = ipmip_cli_history_get(daemon);
ipcom_printf("Current History: %u"IP_LF, val);
}
else if (op_val == 2)
{
/* CONFIG */
/* Time to retrieve data regarding this particular network */
while ((i = ipcom_getopt_r(argc - 1, argv + 1, "n:a", &opt)) != -1)
{
switch (i)
{
case 'a':
break;
case 'n':
name = opt.optarg;
break;
default:
ipcom_printf("invalid option '%c'"IP_LF, i);
goto exit_out;
}
}
ipmip_cli_config_print(proc, daemon, name);
}
else if (op_val == 3)
{
int evop = 0;
int consumed = 1;
if (argc > 3)
{
if (argv[2][0] != '-')
{
evop = ipcom_cmd_str_to_key(events_ops, argv[2]);
if (evop == -1)
{
ipcom_printf("Unknown events subcommand %s"IP_LF, argv[2]);
goto exit_out;
}
else
consumed++;
}
}
if (evop == 0)
{
int lvl = IPCOM_LOG_DEBUG2;
/* Skip two args; */
/* Time to retrieve data regarding this particular network */
while ((i = ipcom_getopt_r(argc - consumed, argv + consumed, "l:", &opt)) != -1)
{
switch (i)
{
case 'l':
lvl = ipmip_util_syslog_priority(opt.optarg);
break;
default:
ipcom_printf("invalid option '%c'"IP_LF, i);
goto exit_out;
}
}
/* EVENTS */
ipmip_cli_event_print(proc, daemon, lvl);
}
else if (evop == 1)
{
ipmip_cli_event_flush(daemon);
}
}
else if (op_val == 4)
{
Ipmip_cli_daemon_req_t req;
int rval;
ipmip_cli_daemon_request_init(&req);
ipmip_cli_daemon_request_start(&req, IPMIP_CLI_TYPE_SYSTEM);
rval = ipmip_cli_daemon_request(daemon, &req);
ipmip_cli_daemon_request_release(&req);
ipcom_printf("returned value '%d'"IP_LF, rval);
}
exit_out:
ipmip_cli_daemon_request_release(&req);
return 0;
}
IP_GLOBAL void
ipmip_cli_shell_usage(Ipmip_proc_t *proc)
{
ipmip_util_cmdprintf(proc, 1, "events flush ", "Flush events from the daemon");
ipmip_util_cmdprintf(proc, 1, "events [get] [-l <loglevel>] ", "Get events from the daemon");
ipmip_util_identprintf(proc, 2, "-l <loglevel> Only list events higher or equal to <loglevel>"IP_LF);
ipmip_util_cmdprintf(proc, 1, "config [-a] [-n <name>] ", "Dump configuration from the daemon");
ipmip_util_identprintf(proc, 2, "-a Dump all configurations"IP_LF);
ipmip_util_identprintf(proc, 2, "-n <name> Only dump configuration from the entity specified by name"IP_LF);
ipmip_util_cmdprintf(proc, 1, "loglevel set <value|priority>", "Set the loglevel to the indicated priority");
ipmip_util_identprintf(proc, 2, "<value> A syslog priority value or number"IP_LF);
ipmip_util_cmdprintf(proc, 1, "loglevel get", "Get the current loglevel");
ipmip_util_cmdprintf(proc, 1, "history set <value>", "Set the history size");
ipmip_util_identprintf(proc, 2, "<value> The new history size"IP_LF);
ipmip_util_cmdprintf(proc, 1, "history get", "Get the history size");
#ifdef IPTESTENGINE
ipmip_util_identprintf(proc, 0, "TEST EXTENSIONS ENABLED" IP_LF);
#endif
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/