JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
SIP API Developer's Guide     Oracle Solaris 11 Express 11/10
search filter icon
search icon

Document Information

Preface

1.  SIP Overview

2.  Oracle Solaris SIP Internals

3.  Multithreading and URI Support

4.  SIP API Functions

A.  Examples of Use

Example of UAS and UAC Use

B.  Programming with the SIP API

C.  Transaction Timers

Index

Example of UAS and UAC Use

Both the UAS and UAC in this section use the following connection object definition and associated functions:

Example A-1 Connection Object Definition for UAS and UAC

    typedef struct my_conn_obj {
            void                    *my_conn_resv;  /* for lib use */
            int                     my_conn_fd;
            struct sockaddr         *my_conn_local;
            struct sockaddr         *my_conn_remote;
            int                     my_conn_transport;
            int                     my_conn_refcnt;
            int                     my_conn_af;
            pthread_mutex_t         my_conn_lock;
            uint32_t                my_conn_flags;
            int                     my_conn_thr;
            int                     my_conn_timer1;
            int                     my_conn_timer2;
            int                     my_conn_timer4;
            int                     my_conn_timerD;
    } my_conn_obj_t;


    int
    my_conn_transport(sip_conn_object_t obj){
        my_conn_obj_t   *conn_obj;
        int             transport;

        conn_obj = (my_conn_obj_t *)obj;
        (void) pthread_mutex_lock(&conn_obj->my_conn_lock);
        transport = conn_obj->my_conn_transport;
        (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);

        return (transport);
    }

    boolean_t
    my_conn_isreliable(sip_conn_object_t obj) {
        my_conn_obj_t   *conn_obj;
        int             transport;

        conn_obj = (my_conn_obj_t *)obj;
        (void) pthread_mutex_lock(&conn_obj->my_conn_lock);
        transport = conn_obj->my_conn_transport;
        (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);

        return (!(transport == IPPROTO_UDP));
    }

    boolean_t
    my_conn_isstream(sip_conn_object_t obj)
    {
        my_conn_obj_t   *conn_obj;
        int             transport;

        conn_obj = (my_conn_obj_t *)obj;
        (void) pthread_mutex_lock(&conn_obj->my_conn_lock);
        transport = conn_obj->my_conn_transport;
        (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);

        return (transport == IPPROTO_TCP);
    }

    void
    my_conn_refhold(sip_conn_object_t obj)
    {
        my_conn_obj_t    *conn_obj;
    
        conn_obj = (my_conn_obj_t *)obj;
    
        (void) pthread_mutex_lock(&conn_obj->my_conn_lock);
        conn_obj->my_conn_refcnt++;
        (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
    }
    
    void
    my_conn_refrele(sip_conn_object_t obj)
    {
        my_conn_obj_t    *conn_obj;
    
        conn_obj = (my_conn_obj_t *)obj;
    
        (void) pthread_mutex_lock(&conn_obj->my_conn_lock);
        if (conn_obj->my_conn_refcnt <= 0) {
            printf("my_conn_refrele: going to break!!\n");
        }
        assert(conn_obj->my_conn_refcnt > 0);
        conn_obj->my_conn_refcnt--;
        if (conn_obj->my_conn_refcnt > 0) {
            (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
            return;
        }
        assert(conn_obj->my_conn_flags & MY_CONN_DESTROYED);
        (void) pthread_mutex_destroy(&conn_obj->my_conn_lock);
        if (conn_obj->my_conn_local != NULL)
            free(conn_obj->my_conn_local);
        if (conn_obj->my_conn_remote != NULL)
            free(conn_obj->my_conn_remote);
        free(conn_obj);
    }
    
    int
    my_conn_local(sip_conn_object_t obj, struct sockaddr *sa,
        socklen_t *len)
    {
        my_conn_obj_t    *conn_obj;
        int        alen;
    
        conn_obj = (my_conn_obj_t *)obj;
        (void) pthread_mutex_lock(&conn_obj->my_conn_lock);
        if (conn_obj->my_conn_local == NULL) {
            (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
            return (-1);
        }
        if (conn_obj->my_conn_local->sa_family == AF_INET)
            alen = sizeof (struct sockaddr_in);
        else
            alen = sizeof (struct sockaddr_in6);
    
        if (*len < alen) {
            (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
            return (EINVAL);
        }
        bcopy(conn_obj->my_conn_local, sa, alen);
        (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
        *len = alen;
        return (0);
    }
    
    int
    my_conn_remote(sip_conn_object_t obj, struct sockaddr *sa,
        socklen_t *len)
    {
        my_conn_obj_t    *conn_obj;
        int        alen;
    
        conn_obj = (my_conn_obj_t *)obj;
        (void) pthread_mutex_lock(&conn_obj->my_conn_lock);
        if (conn_obj->my_conn_remote == NULL) {
            (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
            return (-1);
        }
        if (conn_obj->my_conn_remote->sa_family == AF_INET)
            alen = sizeof (struct sockaddr_in);
        else
            alen = sizeof (struct sockaddr_in6);
    
        if (*len < alen) {
            (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
            return (EINVAL);
        }
        bcopy(conn_obj->my_conn_remote, sa, alen);
        (void) pthread_mutex_unlock(&conn_obj->my_conn_lock);
        *len = alen;

        return (0);
    }
    
    int
    my_conn_send(const sip_conn_object_t obj, char *msg, int msglen)
    {
        my_conn_obj_t    *conn_obj;
        size_t        nleft;
        int        nwritten;
        const char    *ptr;
        socklen_t    tolen;
    
        conn_obj = (my_conn_obj_t *)obj;
        if (conn_obj->my_conn_fd == NULL)
            return (EINVAL);
    
        ptr = msg;
        nleft = msglen;
    
        if (conn_obj->my_conn_remote->sa_family == AF_INET)
            tolen = sizeof (struct sockaddr_in);
        else
            tolen = sizeof (struct sockaddr_in6);
    
        while (nleft > 0) {
            if (conn_obj->my_conn_transport == IPPROTO_UDP) {
                if ((nwritten = sendto(conn_obj->my_conn_fd,
                    ptr, nleft, 0, conn_obj->my_conn_remote,
                    tolen)) <= 0) {
                    return (-1);
                }
            } else {
                if ((nwritten = write(conn_obj->my_conn_fd, ptr,
                    nleft)) <= 0) {
                    return (-1);
                }
            }
            nleft -= nwritten;
            ptr += nwritten;
        }
        return (0);
    }

Additionally, both UAS and UAC register the following transaction and dialog state transition callback functions:

Example A-2 Transaction and Dialog State Transition Callback Functions for UAS and UAC

void
    ulp_dialog_state_cb(sip_dialog_t dialog, sip_msg_t sip_msg,
        int pstate, int nstate)
    {
        printf("\t\t\t%p %d ==> %d\n", dialog, pstate, nstate);
    }

    void
    ulp_trans_state_cb(sip_transaction_t sip_trans, sip_msg_t sip_msg,
        int pstate, int ostate)
    {
        char            *bid;
        sip_method_t    method;
        int        err;

        /* Not checking for err in the following functions */
        if (sip_msg != NULL) {
            if (sip_msg_is_request(sip_msg, &err)) {
                method = sip_get_request_method(sip_msg, &err);
            } else {
                method = sip_get_callseq_method(sip_msg, NULL,
                    &err);
            }
        }
        bid = sip_get_trans_branchid(sip_trans);
        printf("\tTransaction (%s) %s\n\t\t\t%d ==> %d\n",
            sip_msg == NULL ? "Null": sip_method_to_str(method),
            bid, pstate, ostate);
        free(bid);
    }

Example A-3 Sample UAS Callback Reception Code

The UAS is a simple server that waits for an INVITE message and responds with a 2xx response and gets an ACK request back.

    void
    my_ulp_recv(sip_conn_object_t obj, sip_msg_t msg,
        sip_dialog_t sip_dialog) {
        sip_msg_t    sip_msg_resp;
        int        resp_code;
        int        error;
        sip_method_t    method;
        char        *totag;

        /* Drop if not a request */
        if (!sip_msg_is_request(msg, &error))
            return;

        method = sip_get_request_method(msg, error);
        if (error != 0)
            return; /* error getting request method);
        if (method == ACK) {
            printf("ACK received\n");
            return;
        }

        if (method != INVITE) {
            printf("not processing %d request\n", method);
            return;
        }

        /* Create an OK  response */
        resp_code = SIP_OK;

        /* This will probably not be  done for each incoming request */
        totag = sip_guid();
        if (totag == NULL) {
            printf("error generating TO tag\n");
            return;
        }
        sip_msg_resp = sip_create_response(msg, resp_code,
            sip_get_resp_desc(resp_code), totag,
            "sip:mycontactinfo@123.1.1.4");
        if (sip_msg_resp == NULL) {
            printf("error creating response\n");
            return;
        }

        /* send message statefully */
        sip_sendmsg(obj, sip_msg_resp, sip_dialog, SIP_SEND_STATEFUL);

        /* free message */
        sip_free_msg(sip_msg_resp);

        /* free totag */
        free(totag);
    }

    /*
     * Main program:
     * Stack initialization:
     *        Stack maintains dialogs.
     *        Dialog and transaction state transition callbacks
     *        registerd.
     */
    sip_stack_init_t    sip_init[1];
    sip_io_pointers_t    sip_io[1];
    sip_ulp_pointers_t    sip_ulp;

    bzero(sip_init, sizeof (sip_stack_init_t));
    bzero(sip_io, sizeof (sip_io_pointers_t));

    sip_io->sip_conn_send = my_conn_send;
    sip_io->sip_hold_conn_object = my_conn_refhold;
    sip_io->sip_rel_conn_object = my_conn_refrele;
    sip_io->sip_conn_is_stream = my_conn_isstream;
    sip_io->sip_conn_is_reliable = my_conn_isreliable;
    sip_io->sip_conn_remote_address = my_conn_remote;
    sip_io->sip_conn_local_address = my_conn_local;
    sip_io->sip_conn_transport = my_conn_transport;

    sip_init->sip_version = SIP_STACK_VERSION;
    sip_init->sip_io_pointers = sip_io;
    bzero(&sip_ulp, sizeof (sip_ulp_pointers_t));
    sip_ulp.sip_ulp_recv = my_ulp_recv;
    sip_init->sip_stack_flags |= SIP_STACK_DIALOGS;
    sip_ulp.sip_ulp_dlg_state_cb = my_dialog_cb;
    sip_ulp.sip_ulp_trans_state_cb = ulp_trans_state_cb;
    sip_init->sip_ulp_pointers = &sip_ulp;

    /* Open a socket and accept a connection */
    sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
    /* Check for socket creation error */

    /* onoff is set to 1 */
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &onoff, sizeof (onoff));
    /* check for setsockopt() error */

    /* fill in bind information in sockaddr_in struct sa */
    bind(sock, sa, slen);
    /* check for bind error */

    listen (sock, 5);

    accept_fd = accept(sock, NULL, NULL);
    /* check for accept error */

    /*
     * create a connection object, nobj is of type my_conn_obj_t
     */
    nobj = malloc(sizeof (my_conn_obj_t));
    /* check for memory failure */

    nobj->my_conn_fd = accept_fd;
    nobj->my_conn_transport = IPPROTO_TCP;
    nobj->my_conn_refcnt = 1;

    /* set address family in nobj->my_conn_af */

    /* Initialize lock */
    (void) pthread_mutex_init(&nobj->my_conn_lock, NULL);

    /* Set local and remote addresses in nobj */

    /* INITIALIZE connection object */
    sip_init_conn_object((sip_conn_object_t)nobj);

    /* Termination not shown */
    for (;;) {
        /*
         * Read incoming message on the connection object
         * my_conn_receive(), not shown, is an application function that
         * reads on nobj->my_conn_fd into buf, nread is the length of
         * the message read.
         */
        nread = my_conn_receive(cobj, buf, MY_BUFLEN);
        /* check for any error */
    
        /* Call into the SIP stack for processing this message */
        sip_process_new_packet((sip_conn_object_t)cobj, buf, nread);
    }

Example A-4 Sample UAC Reception Code

The UAC is a simple client that sends an INVITE and responds with an ACK when it gets a 2xx final response.

    /* dialog not used */
    void
    my_ulp_recv(sip_conn_object_t obj, sip_msg_t msg,
        sip_dialog_t sip_dialog)
    {
        sip_msg_t               ack_msg;
        uint32_t                resp;
        int                     resp_code;
        int            err;
        int            transport;

        /* Not checking for err */
        if (sip_msg_is_request(msg, &err)) {
            printf("received request\n");
            return;
        }
        resp_code = sip_get_response_code(msg);
        if (sip_get_callseq_method(msg, NULL, &err) != INVITE) {
            printf("received response non-invite\n");
            return;
        }

        if (!SIP_OK_RESP(resp_code)) {
            printf("received non-2xx response %d\n", resp_code);
            return;
        }
        
         ack_msg = sip_new_msg();
         /* check for null ack_msg */

        transport = my_conn_transport(obj);

        sip_create_OKack(msg, ack_msg,
            sip_proto_to_transport(transport));
        /* check for failure */


        /* Send the ACK message */
        sip_sendmsg(obj, ack_msg, sip_dialog, SIP_SEND_STATEFUL);

        /* free message */
        sip_free_msg(ack_msg);
    }

    /* Function to create an request */
    sip_msg_t
    my_get_sip_req_msg(sip_method_t method, char *from_name,
        char *from_uri, char *to_name, char *to_uri, char *from_tag,
        char *to_tag, char *contact, char *transport, char *via_param,
        char *sent_by, uint_t max_forward, uint_t cseq, char *callid)
    {
        sip_msg_t    sip_msg;

        sip_msg = sip_new_msg();
        /* check for memory failure */

        /* Check for failure in each case below */

        /* Add request line */
        sip_add_request_line(sip_msg, method, to_uri);

        /* Add FROM */
        sip_add_from(sip_msg, from_name, from_uri, from_tag, B_TRUE,
            NULL);

        /* Add TO */
        sip_add_to(sip_msg, to_name, to_uri, to_tag, B_TRUE, NULL);

        /* Add CONTACT */
        sip_add_contact(sip_msg, NULL, contact, B_TRUE, NULL);

        /* Add VIA, no port */
        sip_add_via(sip_msg, transport, sent_by, 0, via_param);

        /* Add Max-Forwards */
        sip_add_maxforward(sip_msg, max_forward);

        /* Add Call-Id */
        sip_add_callid(sip_msg, callid);

        /* Add Cseq */
        sip_add_cseq(sip_msg, method, cseq);
    }


    /*
     * Main program:
     * Stack initialization:
     *        Stack maintains dialogs.
     *        Dialog and transaction state transition callbacks
     *        registerd.
     */
    sip_stack_init_t    sip_init[1];
    sip_io_pointers_t    sip_io[1];
    sip_ulp_pointers_t    sip_ulp;

    bzero(sip_init, sizeof (sip_stack_init_t));
    bzero(sip_io, sizeof (sip_io_pointers_t));

    sip_io->sip_conn_send = my_conn_send;
    sip_io->sip_hold_conn_object = my_conn_refhold;
    sip_io->sip_rel_conn_object = my_conn_refrele;
    sip_io->sip_conn_is_stream = my_conn_isstream;
    sip_io->sip_conn_is_reliable = my_conn_isreliable;
    sip_io->sip_conn_remote_address = my_conn_remote;
    sip_io->sip_conn_local_address = my_conn_local;
    sip_io->sip_conn_transport = my_conn_transport;

    sip_init->sip_version = SIP_STACK_VERSION;
    sip_init->sip_io_pointers = sip_io;
    bzero(&sip_ulp, sizeof (sip_ulp_pointers_t));
    sip_ulp.sip_ulp_recv = my_ulp_recv;
    sip_init->sip_stack_flags |= SIP_STACK_DIALOGS;
    sip_ulp.sip_ulp_dlg_state_cb = my_dialog_cb;
    sip_ulp.sip_ulp_trans_state_cb = ulp_trans_state_cb;
    sip_init->sip_ulp_pointers = &sip_ulp;

    /* Open a socket and accept a connection */
    sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
    /* Check for socket creation error */

    /* connect to peer - sa is filled appropriately with peer info. */
    connect(sock, sa, slen);
    /* check for connect failure */


    /*
     * create a connection object, nobj is of type my_conn_obj_t
     */
    obj = malloc(sizeof (my_conn_obj_t));
    /* check for memory failure */

    obj->my_conn_fd = accept_fd;
    obj->my_conn_transport = IPPROTO_TCP;
    obj->my_conn_refcnt = 1;

    /* set address family in obj->my_conn_af */

    /* Initialize lock */
    (void) pthread_mutex_init(&obj->my_conn_lock, NULL);

    /* Set local and remote addresses in obj */

    /* INITIALIZE connection object */
    sip_init_conn_object((sip_conn_object_t)obj);

    /* Create an INVITE request */
    req_msg = my_get_sip_req_msg(INVITE, "me", "sip:me@mydomain.com",
        "you", "sip:user@example.com", "tag-from-01", NULL,
        "sip:myhome.host.com",
        sip_proto_to_transport(obj->my_conn_transport),
        "branch=z9hG4bK-via-01", "123.1.2.3", 70, 111, NULL);

    /* Send request statefully */
    sip_sendmsg((sip_conn_object_t)obj, req_msg, NULL, SIP_SEND_STATEFUL);

    /* free msg */
    sip_free_msg(req_msg);


    /* Termination condition not shown */
    for (;;) {
        /*
         * Read incoming message on the connection object
         * my_conn_receive(), not shown, is an application function that
         * reads on nobj->my_conn_fd into buf, nread is the length of
         * the message read.
         */
        nread = my_conn_receive(obj, buf, MY_BUFLEN);
        /* check for any error */
    
        /* Call into the SIP stack for processing this message */
        sip_process_new_packet((sip_conn_object_t)obj, buf, nread);
    }