Skip Navigation Links | |
Exit Print View | |
SIPAPI Developer's Guide Oracle Solaris 11.1 Information Library |
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); }