« Using Apple's PPP Library

Posted by Andy Monitzer on July 24, 2001 [Feedback (2) & TrackBack (0)]

// What's That?

This tutorial is about how to control the PPP-connection. It might not be very interesting to most programmers, but maybe some people can use this information for making the life better for dialup users.

 

// What It Can Do For You

The PPP-library Apple provides you to connect to a PPP-server, disconnect, set and get some connection information (connection time, data transferred...) and receive events. Note that this is a C-API, but it works fine in Objective C.

 

// What You Need

First you have to get some code from Darwin's cvs (see Apple's site for information how to get access). The module is called "ppp":

cvs -z3 -d :pserver:user@anoncvs.publicsource.apple.com:/cvs/Darwin co ppp

Now go into the directory "SampleCode/ClientAPI". Copy ppplib.h and ppplib.c to your project. Then go into "Controller". Pick up ppp_msg.h and copy that one, too.

Add those to your project (don't forget into insert them into the proper target).

 

// Extending

To add the ability to receive events, add the following to ppplib.c (those are additions by me):

/* -----------------------------------------------------------------------------
enable receiving of events
parameters :
     ref : reference for this client
return code
     errPPPNoError :
----------------------------------------------------------------------------- */
int PPPEnableEvent(int ref) {
    struct ppp_msg_hdr msg;
    
    bzero(&msg, sizeof(msg));
    msg.m_type = PPP_ENABLE_EVENT;
    
    if(write(ref, &msg, sizeof(msg)) != sizeof(msg)) {
        return errno;
    }
    if (read(ref, &msg, sizeof(msg)) != sizeof(msg)) {	  // always expect a reply
       return errno;
    }
    return msg.m_result;
}

/* -----------------------------------------------------------------------------
disable receiving of events
parameters :
     ref : reference for this client
return code
     errPPPNoError :
----------------------------------------------------------------------------- */
int PPPDisableEvent(int ref) {
    struct ppp_msg_hdr msg;
    
    bzero(&msg, sizeof(msg));
    msg.m_type = PPP_DISABLE_EVENT;
    
    if(write(ref, &msg, sizeof(msg)) != sizeof(msg)) {
        return errno;
    }
    if (read(ref, &msg, sizeof(msg)) != sizeof(msg)) {   // always expect a reply
       return errno;
    }

    return msg.m_result;
}

/* -----------------------------------------------------------------------------
wait for an event (blocks)
parameters :
     ref : reference for this client
     msg : the returned event message (reference)
return code
     errPPPNoError :
----------------------------------------------------------------------------- */
int PPPWaitForEvent(int ref, struct ppp_msg_hdr *msg) {
    fd_set read_set;

    FD_ZERO(&read_set);
    FD_SET(ref,&read_set);
    
    if(select(ref+1, &read_set, NULL, NULL, NULL)<0)
        return errno;
    
    if(read(ref,msg,sizeof(*msg))!=sizeof(*msg))
        return errno;

    return 0;
}

And the following to ppplib.h:

int PPPEnableEvent(int ref);
int PPPDisableEvent(int ref);
int PPPWaitForEvent(int ref, struct ppp_msg_hdr *msg);

And replace the #include-line with #include "ppp_msg.h".

 

// Using ppplib

First, you have to establish a connection to the PPP-controller:

#include "ppplib.h"
int ref;
PPPInit(&ref,0,0);

"ref" is the reference to your connection. You need this for all commands. The other two parameters aren't used and are here for compatibility reasons.

Now you can send commands. For instance, to connect use the following:

PPPConnect(ref);

To disconnect:

PPPDisonnect(ref);

The status information is pretty interesting:

struct ppp_status state;
PPPStatus(ref,&state);

The struct that is used here is defined in ppp_msg.h:

struct ppp_status {
    // connection stats
    u_int32_t 		status;
    union {
        struct connected {
            u_int32_t 		timeElapsed;
            u_int32_t 		timeRemaining;
            // bytes stats
            u_int32_t 		inBytes;
            u_int32_t 		inPackets;
            u_int32_t 		inErrors;
            u_int32_t 		outBytes;
            u_int32_t 		outPackets;
            u_int32_t 		outErrors;
        } run;
        struct disconnected {
            u_int32_t 		lastDiscCause;
        } disc;
    } s;
};

To get a clue what constants are used (for instance for ppp_status.status), take a look at ppp_msg.h:

// state machine
enum {
    PPP_IDLE = 0,
    PPP_INITIALIZE,
    PPP_CONNECTLINK,
    PPP_STATERESERVED,
    PPP_ESTABLISH,
    PPP_AUTHENTICATE,
    PPP_CALLBACK,
    PPP_NETWORK,
    PPP_RUNNING,
    PPP_TERMINATE,
    PPP_DISCONNECTLINK
};

Don't forget to dispose the reference when done:

PPPDispose(ref);

 

// Events

You might want to know when a connection is established and closed. One way to do this is to constantly poll using PPPStatus(ref);, but that's not very efficient.

The best (maybe not the easiest) way is to use my additions, PPPEnableEvent/PPPDisableEvent/PPPWaitForEvent. To enable and disable receiving events:

PPPEnableEvent(ref);
PPPDisableEvent(ref);

When receiving events is enabled, you can wait for an event using PPPWaitForEvent. Note that this function blocks until something is received, so it's wise to put it into a separate thread.

struct ppp_msg_hdr msg;
PPPWaitForEvent(ref, &msg);

To get the information what event has happend, read the struct ppp_msg_hdr:

struct ppp_msg_hdr {
    u_int32_t 		m_type; 	// type of the message
    u_int32_t 		m_result; 	// error code of notification message
    u_int32_t 		m_cookie;	// user param
    u_int32_t 		m_link;		// link for this message
    u_int32_t 		m_len;		// len of the following data
};

// events
enum {
    PPP_EVT_DISCONNECTED = 1,
    PPP_EVT_CONNSCRIPT_STARTED,
    PPP_EVT_CONNSCRIPT_FINISHED,
    PPP_EVT_TERMSCRIPT_STARTED,
    PPP_EVT_TERMSCRIPT_FINISHED,
    PPP_EVT_LOWERLAYER_UP,
    PPP_EVT_LOWERLAYER_DOWN,
    PPP_EVT_LCP_UP,
    PPP_EVT_LCP_DOWN,
    PPP_EVT_IPCP_UP,
    PPP_EVT_IPCP_DOWN,
    PPP_EVT_AUTH_STARTED,
    PPP_EVT_AUTH_FAILED,
    PPP_EVT_AUTH_SUCCEDED
};

 

// Conclusion

There are some more options, for example you can set the modem script used or get your IP address. Take a look at ppplib.h and ppp_msg.h for more information.

The ppplib Apple provides is pretty easy to use, so I'm waiting for you programmers helping those poor dialup users!


Comments

Hello,
Please tell me where is the PPP-library. I didn't found the source.
Thanks.

Posted by: Michaël on February 1, 2003 06:04 AM

hello,
I'd like to use the PPP library to configure and run a DSL connection using PPPoE protocol. Is there a function call like PPPConnect to do that. Maybe that's just an option I have to specify but I don't kown which one nor how to do that.

regards

mathieu

Posted by: mamat on November 12, 2003 10:40 AM
Post a comment