You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/erlang/epmd.c

151 lines
3.7 KiB

/**
* Copyright (C) 2015 Bicom Systems Ltd, (bicomsystems.com)
*
* Author: Seudin Kasumovic (seudin.kasumovic@gmail.com)
*
* This file is part of Kamailio, a free SIP server.
*
* Kamailio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* Kamailio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <ei.h>
#include <netinet/ip.h> /*IPTOS_LOWDELAY*/
#include "../../dprint.h"
#include "../../ip_addr.h"
#include "mod_erlang.h"
#include "erl_helpers.h"
#include "epmd.h"
#include "cnode.h"
#ifndef CONNECT_TIMEOUT
#define CONNECT_TIMEOUT 500 /* ms */
#endif
/**
* \brief Initialize EPMD handler
*/
int epmd_init(epmd_handler_t *epmd, str *alivename)
{
epmd->sockfd = erl_init_node(&epmd->ec, alivename, &cnode_host, &cookie);
epmd->handle_f = handle_epmd;
epmd->wait_tmo_f = NULL;
epmd->destroy_f = NULL;
epmd->new = NULL;
return epmd->sockfd;
}
/**
* \brief Handle connections from epmd.
*/
int handle_epmd(handler_common_t *phandler)
{
struct ip_addr ip;
struct sockaddr addr = { 0 };
struct sockaddr *paddr;
socklen_t addrlen = sizeof(struct sockaddr);
int port;
int ai_error;
int sockfd;
int on;
epmd_handler_t *me;
cnode_handler_t *remotenode = NULL;
ErlConnect conn;
paddr = &addr;
me = (epmd_handler_t*) phandler;
if ((sockfd = ei_accept_tmo(&me->ec, me->sockfd, &conn, CONNECT_TIMEOUT))
== ERL_ERROR) {
LM_ERR("error on accept connection: %s.\n", strerror(erl_errno));
if (erl_errno == ETIMEDOUT) {
return 0;
} else if (errno) {
LM_ERR("socket error: %s\n", strerror(errno));
return -1;
} else {
/* if errno didn't get set, assume nothing *too much* horrible occurred */
LM_NOTICE("ignored error in ei_accept, probably: bad client version, "
"bad cookie or bad node name\n");
}
return 0;
}
/* get remote address info of connected socket */
if ((ai_error = getpeername(sockfd, paddr, &addrlen)))
{
LM_ERR("%s\n",strerror(errno));
}
else
{
sockaddr2ip_addr(&ip,paddr);
port = sockaddr_port(paddr);
LM_DBG("connected from %s port %u\n", ip_addr2strz(&ip), port);
}
remotenode = (cnode_handler_t*)pkg_malloc(sizeof(cnode_handler_t));
if (!remotenode) {
erl_close_socket(sockfd);
return -1;
}
/* tos */
on=IPTOS_LOWDELAY;
if (setsockopt(sockfd, IPPROTO_IP, IP_TOS, (void*)&on,sizeof(on)) ==-1) {
LM_WARN("setsockopt set tos failed: %s\n", strerror(errno));
/* continue since this is not critical */
}
if (erl_set_nonblock(sockfd)){
LM_ERR("set non blocking socket failed\n");
}
memset((void*)remotenode,0,sizeof(cnode_handler_t));
remotenode->handle_f = handle_cnode;
remotenode->wait_tmo_f = wait_cnode_tmo;
remotenode->destroy_f = destroy_cnode;
remotenode->sockfd = sockfd;
remotenode->ec = me->ec;
remotenode->conn = conn;
/* for #Pid */
remotenode->ec.self.num = sockfd;
if (ei_x_new(&remotenode->request))
{
LOG(L_ERR,"failed to allocate ei_x_buff: %s.\n", strerror(erl_errno));
return -1;
}
if (ei_x_new_with_version(&remotenode->response))
{
LOG(L_ERR,"failed to allocate ei_x_buff: %s.\n", strerror(erl_errno));
return -1;
}
phandler->new = (handler_common_t*)remotenode;
/* activate node */
enode = remotenode;
return 0;
}