Save running config stuck forever

Dear Team,

When CLI command like below is issued would like to save the running configuration

# show servers server name smtp

To achive this used maapi_save_config() API’s.
Noticed while reading of buffer from stream socket it stuck forever.
Below Code snippet is added in action callback of above CLI command

callback_of_show_server ()
{
/* first we need a maapi socket */    
  if ((msock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )        
    confd_fatal("Failed to open socket\n");
  if (maapi_connect(maapi_socket, (struct sockaddr*)&addr,sizeof (struct sockaddr_in)) < 0)
  confd_fatal("Failed to confd_connect() to confd \n");

   maapi_set_user_session(msock,usid);
   th = maapi_start_trans(msock, dbname, CONFD_READ)) >= 0);  //SUCCESS
   int id = maapi_save_config(msock, th, MAAPI_CONFIG_XML_PRETTY, "/system");//SUCCESS

   //Open another socket ssock confd_stream_connect
   if ((ssock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
   {
     confd_fatal("Failed to open socket\n");
   }

   if(confd_stream_connect(ssock, (struct sockaddr*)&paddr,  sizeof(struct sockaddr_in), id, 0) == CONFD_OK) //SUCCESS
   {
     //Some Code
   }
 
    f = fopen("filename.xml"); //SUCCESS
   //Always num of bytes read always zero ,hence went to infinite loop.Why?
   while ((r = read(ssock, buf, sizeof(buf))) > 0) {
     if (fwrite(buf, 1, r, f) != r)
     confd_fatal("Failed to write output\n");
   }
    if (r < 0)
     confd_fatal("Failed to read from stream socket\n");

OR

   bytes_read = recv(ssock, buffer, BUFSIZ - 1, 0); //bytes_read is zero.Why?
   while (bytes_read > 0)
   {
     buffer[bytes_read] = 0; // Null-terminate the buffer
     bytes_read = recv(ssock, buffer, BUFSIZ - 1, 0);
   }
   if(bytes_read == -1)
   {
     cout<<"read from stream socket failed\n");
   }

    close(ssock);

    if(maapi_save_config_result(msock, id) == CONFD_OK){} //These API are not executed
    if(maapi_finish_trans(msock, th) == CONFD_OK){} //These API are not executed
}

Why bytes read from stream socket is always 0 ?
Could you please help.

Thanks in advance

Hello,

I have tried to create working example, you can find it here (see RADEM file)

https://cisco.box.com/s/uccvlw1up3j9meukf7bf17x1ut06vo65

I do not know exactly what is wrong with your code

I use

 maapi_attach2(maapisock, maapi_example__ns, uinfo->usid,  uinfo->actx.thandle

instead of trying to attach to existing command transaction, not maapi_start_trans.

You may also check (devel.log), if save command does not call any of your code and since it is blecked in ConfD loop, it would get stuck (even though for CONFIG it should be OK).

I suggest to verify the example works in your environment and if does, then compare your implmentation for differences. Hopefully it helps (requires confd-6.4.1 and newer for trace.h - otherwise comment out all TRACE, FATAL lines and replace with printf).

The action callback from example looks like:

int do_show_save_system(struct confd_user_info *uinfo, char *path, int argc_in,
        char **argv_in)
{
    TRACE_ENTER("path %s argc_in=%d", path, argc_in);
    int rv = CONFD_ERR;
    if (argc_in != 2) { //command string + value = 2 arguments
        FATAL("Wrong number of arguments %i, expected 2", argc_in);
        goto term;
    }
    TRACE("filename is argv_in[1]=%s", argv_in[1]);
    //maapi_set_user_session(maapisock, uinfo->usid);
    int ssock, r;
    char buf[BUFSIZ];

    if (CONFD_OK != maapi_attach2(maapisock, example__ns, uinfo->usid,
                    uinfo->actx.thandle)) {
        FATAL("Failed to attach to maapi!");
        goto term;
    }

    int id = maapi_save_config(maapisock, uinfo->actx.thandle,
    MAAPI_CONFIG_XML_PRETTY, "/system");
    if (id == CONFD_ERR) {
        FATAL("Failed to get save id");
        goto term;
    }
    TRACE("Opening stream socket");

    if ((ssock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        FATAL("Failed to open socket");
        goto term;
    }

    if (confd_stream_connect(ssock, (struct sockaddr*) &addr,
            sizeof(struct sockaddr_in), id, 0) != CONFD_OK) {
        FATAL("Failed to connect confd_stream");
        goto term;
    }
    TRACE("Saving stream");

    FILE* f = fopen(argv_in[1], "w");
    while ((r = read(ssock, buf, sizeof(buf))) > 0) {
        if (fwrite(buf, 1, r, f) != r) {
            FATAL("Failed to write output");
            goto term;
        }
    }
    TRACE("stream saved");
    fclose(f);
    close(ssock);
    if (r < 0) {
        FATAL("Failed to read from stream socket\n");
        goto term;
    }

    if (maapi_save_config_result(maapisock, id) != CONFD_OK) {
        FATAL("Not all config received!");
        goto term;
    }

    rv = CONFD_OK;
    term: TRACE_EXIT("rv=%i", rv);
    return rv;
}

Thank you Michal!!!
All the mappi calls are successfull.
I noticed it stuck forever at while ((r = read(ssock, buf, sizeof(buf))) > 0)

Even I tried using threads like

callback_of_show_server
{

   /* Establish a MAAPI socket */
if (0 > (maapisock = socket(PF_INET, SOCK_STREAM, 0))) {
    FATAL("Failed to open socket\n");
    goto term;
}

if (CONFD_OK
        != maapi_connect(maapisock, (struct sockaddr*) &addr,
                sizeof(struct sockaddr_in))) {
    FATAL("Failed to confd_connect() to confd!");
    goto term;
}

boost::thread workerThread(show_runninig_handler);
workerThread.join();

}

void show_runninig_handler()
{
std::string cmd = “show running-config | save filename.xml”;
maapi_cli_printf(gsock, gsid, “\nStart:show_runninig_handler\n”);
boost::posix_time::seconds workTime(2);
boost::this_thread::sleep(workTime);
maapi_cli_cmd(gsock, gsid, cmd.c_str(), cmd.length());
maapi_cli_printf(gsock, gsid, “\nEnd:show_runninig_handler\n”); < -----This print is not seen
}

We also noticed ,in both approach getNext is NOT called.

Hello,

I assume example I have posted works.

“We also noticed ,in both approach getNext is NOT called.”

Why would you expect get_next (operational data?)to be called when you are saving config data? Do you have some external database?

If you are using only one confd loop and one worker socket, then of course get_next cannot be called, as
you application is already blocked by action callback.

Solution is to have another poll loop in separate thread and handled by other worker socket - e.g. handle get_next with workersock in loop 1 and handle action callback with workersock2 in loop 2.

Example of more threads and workersockets (even though not so appropriate for this case) is in 9-c_threads directory.

Dear Michal,

Thank you!!!
Yes we have external DB.
Will check 9-c_threads.

Thanks and Regards
Prabhudev