tfSntpUserExecute

Jump to: navigation, search

Table of Contents >> Application Reference >> Simple Network Time Protocol


#include <trsocket.h>


int tfSntpUserExecute (ttSntpHandle sntpHandle);


Function Description

Start and run the SNTP client. This function receives events, processes them and notifies you by way of the event callback function you specified in tfSntpUserCreate().

If the association was created in blocking mode, your application calls tfSntpUserExecute() once from a dedicated task (see the Multithreaded Example below). When there are no events to process, tfSntpUserExecute() blocks until awakened by the next event. The function returns when you call tfSntpUserClose() or an error prevents further execution.

Event type TM_SNTP_EVENT_ERROR is only signaled in blocking mode. Since a blocking mode tfSntpUserExecute() call only returns when the association is closed, Treck SNTP uses TM_SNTP_EVENT_ERROR to signal non-fatal errors. Your application decides what action is warranted in response to this event.

If the association was created in non-blocking mode, your application calls tfSntpUserExecute() periodically to service outstanding events. The function returns when there are no events to process or an error occurs. Error codes are returned to the user without closing the association.

Some error codes may be transient in nature. After a power outage, for example, your SNTP client may start requesting time updates before an NTP server on the same network has initialized. In this case, you may see TM_EHOSTUNREACH errors in response to ICMP port unreachable packets or you may get TM_SNTP_EVENT_KISS events with the INIT kiss code.

Two additional event types are available for non-blocking mode: TM_SNTP_EVENT_SOCKET for a socket event (e.g. a received packet) and TM_SNTP_EVENT_TIMER for a timer event (e.g. the poll interval timer expired). These events occur asynchronously to your tfSntpUserExecute() call and are the only events that are not signaled from tfSntpUserExecute(). They are provided for your convenience, as an alternative to fixed interval calls, and tell you exactly when you need to call tfSntpUserExecute(). Reducing the time between the arrival of a time update packet and your call to tfSntpUserExecute() will give you better time accuracy and avoid unnecessary calls. For these additional events, you must not call any function that could block or perform I/O (e.g. printf()) or delay the calling context unduly. To do so would affect all sockets and timers. Instead, set a global flag or signal your main event loop to call tfSntpUserExecute() (see the Event Loop Example below).


Multithreaded Example

#include "trsocket.h"
 
/*
 * User function to spawn the SNTP task.
 */
int mySntpFunction(void)
{
    struct sockaddr_storage sockAddr;
    ttSntpHandle            sntpHandle;
    int                     errorCode;
 
    .  .  .
 
/* Create a unicast SNTP client */
    sntpHandle = tfSntpUserCreate(&sockAddr, mySntpNotifyFunc, TM_BLOCKING_ON, &errorCode);
    assert((sntpHandle != TM_SNTP_INVALID_HANDLE) && (errorCode == TM_ENOERROR));
 
/* Start a background thread for the SNTP client (O/S specific) */
    KernelSpawnTask(mySntpTask, sntpHandle);
 
    .  .  .
}
 
/*
 * Background SNTP task code.
 */
void mySntpTask(ttSntpHandle sntpHandle)
{
    int errorCode;
 
/* Run the SNTP client */
    errorCode = tfSntpUserExecute(sntpHandle);
    assert(errorCode == TM_ENOERROR);
}
 
/*
 * SNTP event handler for the association.
 */
void mySntpNotifyFunc(
    ttSntpHandle        sntpHandle,
    const void TM_FAR * paramPtr,
    int                 eventId)
{
    .  .  .
 
    switch (eventId)
    {
        .  .  .
    }
 
    .  .  .
}


Event Loop Example

#include "trsocket.h"
 
KernelEventObject mySntpEvent;  /* kernel specific event synchronization object */
 
/*
 * User function to create and run the SNTP task.
 */
int mySntpFunction(void)
{
    struct sockaddr_storage sockAddr;
    ttSntpHandle            sntpHandle;
    int                     errorCode;
 
    .  .  .
 
/* Create a unicast SNTP client */
    sntpHandle = tfSntpUserCreate(&sockAddr, mySntpNotifyFunc, 0, &errorCode);
    assert((sntpHandle != TM_SNTP_INVALID_HANDLE) && (errorCode == TM_ENOERROR));
 
/* Run the SNTP client */
    for (;;)
    {
        errorCode = tfSntpUserExecute(sntpHandle);
        if (errorCode != TM_ENOERROR)
        {
            break;
        }
 
/* Kernel specific event synchronization */
        KernelWaitForEvent(mySntpEvent);
    }
 
    .  .  .
}
 
/*
 * SNTP event handler for the association.
 */
void mySntpNotifyFunc(
    ttSntpHandle        sntpHandle,
    const void TM_FAR * paramPtr,
    int                 eventId)
{
    .  .  .
 
    switch (eventId)
    {
 
        .  .  .
 
    case TM_SNTP_EVENT_SOCKET:   /* socket event */
    case TM_SNTP_EVENT_TIMER:    /* timer event */
/* Kernel specific event synchronization */
        KernelSignalEvent(mySntpEvent);
        break;
 
        .  .  .
 
    }
 
    .  .  .
}


Parameters


Returns

  • TM_ENOERROR
    Success.
  • TM_EINVAL
    Invalid handle.
  • TM_EPERM
    Call tfSntpUserBind() first, for a broadcast client.
  • TM_ENOBUFS
    Not enough memory.
  • TM_ESHUTDOWN
    Descriptor is closed.
  • (more)
    Other socket errors are possible. See tfZeroCopyRecvFrom() and tfZeroCopySend().


Table of Contents >> Application Reference >> Simple Network Time Protocol