implement simplistic UDP transport for TCAP

Normally, TCAP is not spoken directly on top of UDP, however this
makes it really easy to test...
This commit is contained in:
Harald Welte 2010-07-17 21:43:00 +02:00
parent aa3011d53e
commit 1e2f04410b
5 changed files with 126 additions and 4 deletions

View File

@ -1,13 +1,17 @@
/* SCCP / SCTP+SUA interface */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <osmocore/logging.h>
#include <osmocore/msgb.h>
#include <osmocore/talloc.h>
#include "tcap_user.h"
#include "tcap.h"
@ -18,14 +22,103 @@ int tcap_tco_n_unitdata_ind(struct tcap_transport_entity *se, struct msgb *msg);
/* prototype of what we need to call in case of incoming NOTICE */
int tcap_tco_n_notice_ind(struct tcap_transport_entity *se);
/***********************************************************************/
/* Simple UDP transport (not according to any kind of official spec) */
/***********************************************************************/
static int tcap_tp_udp_unitdata_req(struct tcap_transport_entity *se, struct msgb *msg)
{
return write_queue_enqueue(&se->udp.write_queue, msg);
}
/* called by the write queue / FD magic in case we need to write a message */
static int udp_write_cb(struct bsc_fd *fd, struct msgb *msg)
{
struct write_queue *wq = container_of(fd, struct write_queue, bfd);
struct tcap_transport_entity *tte = container_of(wq, struct tcap_transport_entity, udp.write_queue);
return sendto(fd->fd, msg->data, msg->len, 0, (struct sockaddr *) &tte->remote_addr, sizeof(tte->remote_addr));
}
/* called by write queue / FD magic in case the socket has some data */
static int udp_read_cb(struct bsc_fd *fd)
{
struct write_queue *wq = container_of(fd, struct write_queue, bfd);
struct tcap_transport_entity *tte = container_of(wq, struct tcap_transport_entity, udp.write_queue);
struct msgb *msg = msgb_alloc_headroom(4096+128, 128, "incoming TCAP/UDP");
socklen_t addr_len = sizeof(tte->remote_addr);
int rc;
if (!msg)
return -ENOMEM;
rc = recvfrom(fd->fd, msg->data, msgb_tailroom(msg), 0,
&tte->remote_addr, &addr_len);
if (rc < 0)
return rc;
msgb_put(msg, rc);
return tcap_tco_n_unitdata_ind(tte, msg);
}
struct tcap_transport_entity *tcap_transp_udp_create(struct sockaddr_storage *local_addr)
{
struct tcap_transport_entity *tte = talloc_zero(NULL, struct tcap_transport_entity);
struct write_queue *wq;
int rc;
if (!tte)
return NULL;
memcpy(&tte->local_addr, local_addr, sizeof(tte->local_addr));
tte->type = SCXP_T_UDP;
/* Initialize write queue */
wq = &tte->udp.write_queue;
write_queue_init(wq, 100);
wq->read_cb = udp_read_cb;
wq->write_cb = udp_write_cb;
wq->bfd.fd = socket(tte->local_addr.ss_family, SOCK_DGRAM, IPPROTO_UDP);
if (wq->bfd.fd < 0)
goto err_free;
rc = bind(wq->bfd.fd, (struct sockaddr *) &tte->local_addr, sizeof(tte->local_addr));
if (rc < 0)
goto err_close;
wq->bfd.when |= BSC_FD_READ;
bsc_register_fd(&wq->bfd);
return tte;
err_close:
close(wq->bfd.fd);
err_free:
talloc_free(tte);
return NULL;
}
/* Called by TCAP stack if it wants to request transmission of UNITDATA */
int tcap_scXp_n_unitdata_req(struct tcap_transport_entity *se, struct msgb *msg)
{
int rc = 0;
printf("N-UNITDATA.req(%s)\n", hexdump(msg->data, msg->len));
#if 0
int i = open("ber.out", O_CREAT|O_WRONLY|O_TRUNC);
write(i, msg->data, msg->len);
close(i);
tcap_tco_n_unitdata_ind(se, msg);
#endif
switch (se->type) {
case SCXP_T_UDP:
rc = write_queue_enqueue(&se->udp.write_queue, msg);
break;
}
return rc;
}

View File

@ -3,6 +3,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
//#include <asn1/OBJECT_IDENTIFIER.h>
#include <osmocore/utils.h>
@ -10,6 +12,7 @@
#include "tcap_user.h"
static struct {
struct tcap_transport_entity *tte;
unsigned int begin_rcvd:1;
uint32_t dialg_id;
} test_state;
@ -64,6 +67,7 @@ static int send_begin(uint32_t dialg_id, OBJECT_IDENTIFIER_t *app_ctx)
memset(&tcdi, 0, sizeof(tcdi));
tcdi.dialg_id = dialg_id;
tcdi.app_ctx_name = app_ctx;
tcdi.transp_ent = test_state.tte;
return tcap_user_req_dialg(TCAP_PR_TC_BEGIN, &tcdi);
}
@ -117,10 +121,30 @@ static int initialize(void)
int main(int argc, char **argv)
{
struct sockaddr_storage ss;
struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
initialize();
ss.ss_family = AF_INET;
sin->sin_addr.s_addr = INADDR_ANY;
sin->sin_port = htons(4242);
test_state.tte = tcap_transp_udp_create(&ss);
if (!test_state.tte) {
fprintf(stderr, "Cannot create UDP socket\n");
exit(1);
}
/* make sure we sent messages to ourselves */
inet_aton("127.0.0.1", &sin->sin_addr);
memcpy(&test_state.tte->remote_addr, &ss, sizeof(test_state.tte->remote_addr));
send_invoke(0x1234, 0, gprs_loc_upd_param, sizeof(gprs_loc_upd_param));
send_invoke(0x1234, 1, NULL, 0);
send_invoke(0x1234, -1, NULL, 0);
send_begin(0x1234, &gprs_loc_upd_ctx_v3_oid);
while (1) {
bsc_select_main(0);
}
}

View File

@ -5,6 +5,7 @@
#include <sys/socket.h>
#include <osmocore/select.h>
#include <osmocore/write_queue.h>
#include <asn1c/OBJECT_IDENTIFIER.h>
#include <osmocom/tcap/Parameter.h>
@ -23,12 +24,12 @@ struct tcap_transport_entity {
/* common parts */
struct sockaddr_storage local_addr;
struct sockaddr_storage remote_addr;
struct bsc_fd socket_fd;
/* type of underlying transport */
enum tcap_transport_entity_type type;
union {
struct {
struct write_queue write_queue;
} udp;
struct {
} sccp_ipa;

View File

@ -186,6 +186,8 @@ int tcap_user_req_dialg(enum tcap_primitive prim, struct tcap_dialg_ind *tcdi)
switch (prim) {
case TCAP_PR_TC_BEGIN:
td = tcap_dialg_alloc(tcdi->dialg_id);
if (!td)
return -EINVAL;
break;
default:
return -EINVAL;
@ -194,6 +196,7 @@ int tcap_user_req_dialg(enum tcap_primitive prim, struct tcap_dialg_ind *tcdi)
switch (prim) {
case TCAP_PR_TC_BEGIN:
td->transp_ent = tcdi->transp_ent;
rc = tcap_csl_tc_begin_req(td, tcdi->app_ctx_name, tcdi->user_info);
break;
case TCAP_PR_TC_CONTINUE:

View File

@ -14,7 +14,7 @@
uint32_t tid_from_octetstr(struct OCTET_STRING *octstr)
{
if (octstr->size != sizeof(uint32_t))
fprintf(stderr, "Transaction ID length != violates spec\n", octstr->size);
fprintf(stderr, "Transaction ID length %u != violates spec\n", octstr->size);
return ntohl(*(uint32_t *)octstr->buf);
}
@ -51,6 +51,7 @@ int tcap_tco_n_unitdata_ind(struct tcap_transport_entity *se, struct msgb *msg)
tt->tid_local = tcap_trans_id_alloc();
/* FIXME: Is TID == no TID ? */
/* Send BEGIN.recv to TSM */
dialg_by_trans(tt)->transp_ent = se;
rc = tcap_tsm_begin_rcvd(tt, tcmsg, msg);
break;
case TCMessage_PR_continue: