/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2015, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* William King <william.king@quentustech.com>
*
* mod_smpp.c -- smpp client and server implementation using libsmpp
*
* using libsmpp from: http://cgit.osmocom.org/libsmpp/
*
*/


#include <mod_smpp.h>

static void *SWITCH_THREAD_FUNC mod_smpp_gateway_read_thread(switch_thread_t *thread, void *obj);

switch_status_t mod_smpp_gateway_create(mod_smpp_gateway_t **gw, char *name, char *host, int port, int debug, char *system_id,
										char *password, char *system_type, char *profile) {
	mod_smpp_gateway_t *gateway = NULL;
	switch_memory_pool_t *pool = NULL;

  	switch_core_new_memory_pool(&pool);

	gateway = switch_core_alloc(pool, sizeof(mod_smpp_gateway_t));

	gateway->pool = pool;
	gateway->running = 1;
	gateway->sequence = 1;
	gateway->name = name ? switch_core_strdup(gateway->pool, name) : "default";
	gateway->host = host ? switch_core_strdup(gateway->pool, host) : "localhost";
	gateway->port = port ? port : 8000;
	gateway->debug = debug;
	gateway->system_id = system_id ? switch_core_strdup(gateway->pool, system_id) : "username";
	gateway->password = password ? switch_core_strdup(gateway->pool, password) : "password";
	gateway->system_type = system_type ? switch_core_strdup(gateway->pool, system_type) : "freeswitch_smpp";
	gateway->profile = profile ? switch_core_strdup(gateway->pool, profile) : "default";

	if ( switch_sockaddr_info_get(&(gateway->socketaddr), gateway->host, SWITCH_INET,
								  gateway->port, 0, mod_smpp_globals.pool) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get socketaddr info\n");
		goto err;
	}

	if ( switch_socket_create(&(gateway->socket), switch_sockaddr_get_family(gateway->socketaddr),
							  SOCK_STREAM, SWITCH_PROTO_TCP, mod_smpp_globals.pool) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create the socket\n");
		goto err;
	}

	switch_mutex_init(&(gateway->conn_mutex), SWITCH_MUTEX_UNNESTED, mod_smpp_globals.pool);
	if (mod_smpp_gateway_connect(gateway) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to connect to gateway[%s]\n", gateway->name);
		goto err;
	}

	/* Start gateway read thread */
	switch_threadattr_create(&(gateway->thd_attr), mod_smpp_globals.pool);
	switch_threadattr_detach_set(gateway->thd_attr, 1);
	switch_threadattr_stacksize_set(gateway->thd_attr, SWITCH_THREAD_STACKSIZE);
	switch_thread_create(&(gateway->thread), gateway->thd_attr, mod_smpp_gateway_read_thread, (void *) gateway, mod_smpp_globals.pool);

	switch_core_hash_insert(mod_smpp_globals.gateways, name, (void *) gateway);

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Gateway %s created\n", gateway->host);

	*gw = gateway;
	return SWITCH_STATUS_SUCCESS;

 err:
	mod_smpp_gateway_destroy(&gateway);
	return SWITCH_STATUS_GENERR;

}

switch_status_t mod_smpp_gateway_authenticate(mod_smpp_gateway_t *gateway) {
    bind_transceiver_t *req_b = calloc(sizeof(bind_transceiver_t), 1);
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_event_t *event = NULL;
	switch_size_t write_len = 0;
	unsigned int command_id = 0;
	uint8_t local_buffer[1024] = {0};
	int local_buffer_len = 1024;

    req_b->command_length   = 0;
    req_b->command_id       = BIND_TRANSCEIVER;
    req_b->command_status   = ESME_ROK;
    req_b->addr_npi         = 1;
    req_b->addr_ton         = 1;

	strncpy( (char *)req_b->address_range, gateway->host, sizeof(req_b->address_range));

	if ( gateway->system_id ) {
		snprintf((char *)req_b->system_id, sizeof(req_b->system_id), "%s",  gateway->system_id);
	}

	if ( gateway->password ) {
		snprintf((char *)req_b->password, sizeof(req_b->password), "%s", gateway->password);
	}

	if ( gateway->system_type ) {
		snprintf((char *)req_b->system_type, sizeof(req_b->system_type), "%s", gateway->system_type);
	}

    req_b->interface_version = SMPP_VERSION;

    mod_smpp_gateway_get_next_sequence(gateway, &(req_b->sequence_number));

	// Not thread safe due to smpp34_errno and smpp34_strerror since they are global to running process.
	// The risk here is that the errno and strerror variables will be corrupted due to race conditions if there are errors
    if ( smpp34_pack2( local_buffer, sizeof(local_buffer), &local_buffer_len, (void*)req_b) != 0 ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error in smpp_pack():%d:\n%s\n", smpp34_errno, smpp34_strerror);
		status = SWITCH_STATUS_GENERR;
		goto done;
	}

	write_len = local_buffer_len;

	if ( mod_smpp_globals.debug || gateway->debug ) {
		mod_smpp_dump_pdu((void *) req_b);
	}

	if ( switch_socket_send(gateway->socket, (char *) local_buffer, &write_len) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send on the socket\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

    if( write_len != local_buffer_len ){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: Was not able to send entire buffer\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	/* Receive the response */
	if ( mod_smpp_gateway_connection_read(gateway, &event, &command_id) != SWITCH_STATUS_SUCCESS){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Authentication failed for gateawy[%s]\n", gateway->name);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	} else {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authentication successful for gateway[%s]\n", gateway->name);
	}

 done:
	if ( (mod_smpp_globals.debug || gateway->debug ) && event ) {
		char *str = NULL;
		switch_event_serialize(event, &str, SWITCH_TRUE);
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Auth response: %s\n", str);
		switch_safe_free(str);
	}

	if ( req_b ) {
		switch_safe_free(req_b);
	}

	return status;
}

/* When connecting to a gateway, the first message must be an authentication attempt */
switch_status_t mod_smpp_gateway_connect(mod_smpp_gateway_t *gateway) {
	switch_status_t status;

	if (gateway->socket) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Closing existing socket\n");
		switch_socket_shutdown(gateway->socket, SWITCH_SHUTDOWN_READWRITE);
		switch_socket_close(gateway->socket);
		gateway->socket = NULL;
	}


	if (!gateway->socket) {
		if ( switch_socket_create(&(gateway->socket), switch_sockaddr_get_family(gateway->socketaddr),
								  SOCK_STREAM, SWITCH_PROTO_TCP, mod_smpp_globals.pool) != SWITCH_STATUS_SUCCESS ) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create the socket\n");
			return SWITCH_STATUS_GENERR;
		}
	}
	
	if ( (status = switch_socket_connect(gateway->socket, gateway->socketaddr)) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to connect the socket %d\n", status);
		return SWITCH_STATUS_GENERR;
	}

	if ( mod_smpp_gateway_authenticate(gateway) != SWITCH_STATUS_SUCCESS ) {
		return SWITCH_STATUS_GENERR;
	}

	return SWITCH_STATUS_SUCCESS;
}

/* Expects the gateway to be locked already */
switch_status_t mod_smpp_gateway_connection_read(mod_smpp_gateway_t *gateway, switch_event_t **event, unsigned int *command_id)
{
	switch_size_t read_len = 4; /* Default to reading only the first 4 bytes to read how large the PDU is */
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	uint8_t *local_buffer = calloc(2048, 1);
	uint32_t *local_buffer32 = (uint32_t *) local_buffer; /* TODO: Convert this into a union */
	switch_event_t *evt = NULL;
	generic_nack_t *gennack = NULL;
    char data[2048] = {0}; /* local buffer for unpacked PDU */
	int err = 0;

	/* Read from socket */
	/* TODO: Add/Expand support for partial reads */
	if ( switch_socket_recv(gateway->socket, (char *) local_buffer, &read_len) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to recv on the socket\n");
	    switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	if ( read_len != 4 ){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error in recv(PEEK) %d\n", (unsigned int )read_len);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	read_len = ntohl(*local_buffer32 );

	if ( read_len > 1500 ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Corrupted PDU size from gateway [%s]\n", gateway->name);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	if ( ( status = switch_socket_recv(gateway->socket, (char *) local_buffer + 4, &read_len)) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to recv on the socket %d\n", status);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	if ( smpp34_unpack2((void *)data, local_buffer, read_len + 4) ) {
		err++;
	}

	if ( mod_smpp_globals.debug || gateway->debug ) {
		mod_smpp_dump_pdu((void *) data);
	}

	gennack = (generic_nack_t *) data;
	*command_id = gennack->command_id;

	if (err && *command_id != SUBMIT_SM_RESP) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,  "smpp: error decoding the receive buffer:%d:%s\n", smpp34_errno, smpp34_strerror);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	switch(*command_id) {
	case BIND_TRANSCEIVER_RESP:
		if ( gennack->command_status != ESME_ROK ) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Authentication Failure %d\n", gennack->command_status);
		}
		break;
	case DELIVER_SM:
		if ( gennack->command_status == ESME_ROK ) {
			deliver_sm_t *res = (deliver_sm_t *) data;

			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New SMS received from[%s] to[%s] message[%s]\n",
							  res->source_addr, res->destination_addr, res->short_message);

			mod_smpp_message_decode(gateway, res, &evt);
		}
		break;
	case ENQUIRE_LINK:
	case ENQUIRE_LINK_RESP:
	case SUBMIT_SM_RESP:
		switch (gennack->command_status) {
		case ESME_ROK:
			//AOK
			break;
		case ESME_RINVSRCADR:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Source Addr ID: %u\n", *command_id);
			break;
		case ESME_RINVDSTADR:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Dest Addr ID: %u\n", *command_id);
			break;
		default:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Undocumented Error 0X%.8x ID: %u\n", gennack->command_status, *command_id);
			break;
		}

		break;
	default:
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unrecognized Command ID: %u\n", *command_id);
	}

	/* Only need to create/expand the event if it is one of the PDU's that we care about */
	if (evt) {
		*event = evt;
	}

 done:
	switch_safe_free(local_buffer);
	return status;
}

static void *SWITCH_THREAD_FUNC mod_smpp_gateway_read_thread(switch_thread_t *thread, void *obj)
{
	mod_smpp_gateway_t *gateway = (mod_smpp_gateway_t *) obj;

	while ( gateway->running ) {
		switch_event_t *event = NULL;
		unsigned int command_id = 0;

		if ( mod_smpp_gateway_connection_read(gateway, &event, &command_id) != SWITCH_STATUS_SUCCESS) {
			if ( gateway->running ) {
				if ( mod_smpp_gateway_connect(gateway) != SWITCH_STATUS_SUCCESS) {
					switch_sleep(1000 * 1000);
				}
			}
			continue;
		}

		if ( (mod_smpp_globals.debug || gateway->debug) && event) {
			char *str = NULL;
			switch_event_serialize(event, &str, 0);
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Received message[%d]:\n%s\n\n", command_id, str);
			switch_safe_free(str);
		}

		switch(command_id) {
		case BIND_TRANSCEIVER_RESP:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Why did we get an unexpected authentication response?\n");
			break;
		case ENQUIRE_LINK:
			mod_smpp_gateway_send_enquire_link_response(gateway);
			break;
		case DELIVER_SM:
			if ( event ) {
				char *str = NULL;
				switch_event_serialize(event, &str, SWITCH_TRUE);
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Inbound SMS packet event: \n%s\n\n", str);
				switch_safe_free(str);
			}

			mod_smpp_gateway_send_deliver_sm_response(gateway, event);

			switch_core_chat_send("smpp", event);
			switch_event_destroy(&event);
			/* Fire message to the chat plan, then respond */
			break;
		case SUBMIT_SM_RESP:
		case ENQUIRE_LINK_RESP:
			break;
		default:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown command_id[%d]\n", command_id);
			if ( event ) {
				char *str = NULL;
				switch_event_serialize(event, &str, SWITCH_FALSE);
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown packet event: %s\n", str);
				switch_safe_free(str);
			}
		}
	}
	return 0;
}

switch_status_t mod_smpp_gateway_send_enquire_link_response(mod_smpp_gateway_t *gateway)
{
    enquire_link_resp_t *enquire_resp = calloc(sizeof(enquire_link_resp_t), 1);
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_size_t write_len = 0;
	uint8_t local_buffer[128] = {0};
	int local_buffer_len = sizeof(local_buffer);

    enquire_resp->command_length   = 0;
    enquire_resp->command_id       = ENQUIRE_LINK_RESP;
    enquire_resp->command_status   = ESME_ROK;

    mod_smpp_gateway_get_next_sequence(gateway, &(enquire_resp->sequence_number));

    if ( smpp34_pack2( local_buffer, sizeof(local_buffer), &local_buffer_len, (void*)enquire_resp) != 0 ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error in smpp_pack():%d:\n%s\n", smpp34_errno, smpp34_strerror);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	write_len = local_buffer_len;

	if ( mod_smpp_globals.debug || gateway->debug ) {
		mod_smpp_dump_pdu((void *) enquire_resp);
	}

	if ( switch_socket_send(gateway->socket, (char *) local_buffer, &write_len) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send on the socket\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

    if( write_len != local_buffer_len ){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: Was not able to send entire buffer\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

 done:
	switch_safe_free(enquire_resp);

	return status;
}

switch_status_t mod_smpp_gateway_send_deliver_sm_response(mod_smpp_gateway_t *gateway, switch_event_t *event)
{
    deliver_sm_resp_t *deliver_sm_resp = calloc(sizeof(deliver_sm_resp_t), 1);
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_size_t write_len = 0;
	uint8_t local_buffer[128] = {0};
	int local_buffer_len = sizeof(local_buffer);

    deliver_sm_resp->command_length   = 0;
    deliver_sm_resp->command_id       = DELIVER_SM_RESP;
    deliver_sm_resp->command_status   = ESME_ROK;
/*	deliver_sm_resp->message_id       = 0;  Not used. calloc defaults to 0 */
	deliver_sm_resp->sequence_number  = atoi(switch_event_get_header(event, "sequence_number"));

    if ( smpp34_pack2( local_buffer, sizeof(local_buffer), &local_buffer_len, (void*)deliver_sm_resp) != 0 ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error in smpp_pack():%d:\n%s\n", smpp34_errno, smpp34_strerror);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	write_len = local_buffer_len;

	if ( mod_smpp_globals.debug || gateway->debug ) {
		mod_smpp_dump_pdu((void *) deliver_sm_resp);
	}

	if ( switch_socket_send(gateway->socket, (char *) local_buffer, &write_len) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send on the socket\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

    if( write_len != local_buffer_len ){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: Was not able to send entire buffer\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

 done:
	switch_safe_free(deliver_sm_resp);
	return status;
}

switch_status_t mod_smpp_gateway_send_unbind(mod_smpp_gateway_t *gateway)
{
    unbind_t *unbind_req = calloc(sizeof(unbind_t), 1);
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_size_t write_len = 0;
	uint8_t local_buffer[128] = {0};
	int local_buffer_len = sizeof(local_buffer);

    unbind_req->command_length   = 0;
    unbind_req->command_id       = UNBIND;
    unbind_req->command_status   = ESME_ROK;

    mod_smpp_gateway_get_next_sequence(gateway, &(unbind_req->sequence_number));

    if ( smpp34_pack2( local_buffer, sizeof(local_buffer), &local_buffer_len, (void*)unbind_req) != 0 ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error in smpp_pack():%d:\n%s\n", smpp34_errno, smpp34_strerror);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	write_len = local_buffer_len;

	if ( mod_smpp_globals.debug || gateway->debug ) {
		mod_smpp_dump_pdu((void *) unbind_req);
	}

	if ( switch_socket_send(gateway->socket, (char *) local_buffer, &write_len) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send on the socket\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

    if( write_len != local_buffer_len ){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: Was not able to send entire buffer\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

 done:
	switch_safe_free(unbind_req);

	return status;
}

switch_status_t mod_smpp_gateway_destroy(mod_smpp_gateway_t **gw)
{
	mod_smpp_gateway_t *gateway = NULL;

	if ( !gw || !*gw ) {
		return SWITCH_STATUS_SUCCESS;
	}

	gateway = *gw;

	switch_core_hash_delete(mod_smpp_globals.gateways, gateway->name);

	gateway->running = 0;

	mod_smpp_gateway_send_unbind(gateway);

	switch_socket_shutdown(gateway->socket, SWITCH_SHUTDOWN_READWRITE);
	switch_socket_close(gateway->socket);

	switch_core_destroy_memory_pool(&(gateway->pool));
	switch_mutex_destroy(gateway->conn_mutex);

	*gw = NULL;
	return SWITCH_STATUS_SUCCESS;
}

switch_status_t mod_smpp_gateway_get_next_sequence(mod_smpp_gateway_t *gateway, uint32_t *seq)
{

	switch_mutex_lock(gateway->conn_mutex);
	gateway->sequence++;
	*seq = gateway->sequence;
	switch_mutex_unlock(gateway->conn_mutex);

	return SWITCH_STATUS_SUCCESS;
}

switch_status_t mod_smpp_gateway_send_message(mod_smpp_gateway_t *gateway, switch_event_t *message) {
	mod_smpp_message_t *msg = NULL;
	uint8_t local_buffer[1024];
	int local_buffer_len = sizeof(local_buffer);
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_size_t write_len = 0;

	if ( mod_smpp_message_create(gateway, message, &msg) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to send message due to message_create failure\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

    memset(local_buffer, 0, sizeof(local_buffer));

    if( smpp34_pack2( local_buffer, sizeof(local_buffer),	&local_buffer_len, (void*)&(msg->req)) != 0 ){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: Unable to encode message:%d:\n%s\n", smpp34_errno, smpp34_strerror);
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	write_len = local_buffer_len;

	if ( mod_smpp_gateway_get_next_sequence(gateway, &(msg->req.sequence_number)) ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to fetch next gateway sequence number\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

	if ( mod_smpp_globals.debug || gateway->debug ) {
		mod_smpp_dump_pdu((void *) &(msg->req));
	}

	if ( switch_socket_send(gateway->socket, (char *) local_buffer, &write_len) != SWITCH_STATUS_SUCCESS ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send on the socket\n");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

    if ( write_len != local_buffer_len ){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: Did not send all of message to gateway");
		switch_goto_status(SWITCH_STATUS_GENERR, done);
	}

 done:
	mod_smpp_message_destroy(&msg);
	return status;
}


/* For Emacs:
 * Local Variables:
 * mode:c
 * indent-tabs-mode:t
 * tab-width:4
 * c-basic-offset:4
 * End:
 * For VIM:
 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
 */
