
net.sourceforge.peers.sip.transport.TransportManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of phone Show documentation
Show all versions of phone Show documentation
This Java SoftPhone base on Peers
/*
This file is part of Peers, a java SIP softphone.
This program 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 3 of the License, or
any later version.
This program 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, see .
Copyright 2007-2013 Yohann Martineau
*/
package net.sourceforge.peers.sip.transport;
import static net.sourceforge.peers.sip.RFC3261.DEFAULT_SIP_VERSION;
import static net.sourceforge.peers.sip.RFC3261.IPV4_TTL;
import static net.sourceforge.peers.sip.RFC3261.PARAM_MADDR;
import static net.sourceforge.peers.sip.RFC3261.PARAM_TTL;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_DEFAULT_PORT;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_PORT_SEP;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_SCTP;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_TCP;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_TLS_PORT;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_UDP;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_UDP_USUAL_MAX_SIZE;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_VIA_SEP;
import static net.sourceforge.peers.sip.RFC3261.TRANSPORT_VIA_SEP2;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Hashtable;
import net.sourceforge.peers.Config;
import net.sourceforge.peers.Logger;
import net.sourceforge.peers.sip.RFC3261;
import net.sourceforge.peers.sip.Utils;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderFieldName;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderFieldValue;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderParamName;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaders;
import net.sourceforge.peers.sip.syntaxencoding.SipParser;
import net.sourceforge.peers.sip.transaction.TransactionManager;
public class TransportManager {
public static final int SOCKET_TIMEOUT = RFC3261.TIMER_T1;
private static int NO_TTL = -1;
private Logger logger;
//private UAS uas;
private SipServerTransportUser sipServerTransportUser;
protected SipParser sipParser;
private Hashtable datagramSockets;
private Hashtable messageSenders;
private Hashtable messageReceivers;
private TransactionManager transactionManager;
private Config config;
private int sipPort;
public TransportManager(TransactionManager transactionManager,
Config config, Logger logger) {
sipParser = new SipParser();
datagramSockets = new Hashtable();
messageSenders = new Hashtable();
messageReceivers = new Hashtable();
this.transactionManager = transactionManager;
this.config = config;
this.logger = logger;
}
public MessageSender createClientTransport(SipRequest sipRequest,
InetAddress inetAddress, int port, String transport)
throws IOException {
return createClientTransport(sipRequest, inetAddress, port, transport,
NO_TTL);
}
public MessageSender createClientTransport(SipRequest sipRequest,
InetAddress inetAddress, int port, String transport, int ttl)
throws IOException {
//18.1
//via created by transaction layer to add branchid
SipHeaderFieldValue via = Utils.getTopVia(sipRequest);
StringBuffer buf = new StringBuffer(DEFAULT_SIP_VERSION);
buf.append(TRANSPORT_VIA_SEP);
if (sipRequest.toString().getBytes().length > TRANSPORT_UDP_USUAL_MAX_SIZE) {
transport = TRANSPORT_TCP;
}
buf.append(transport);
if (inetAddress.isMulticastAddress()) {
SipHeaderParamName maddrName = new SipHeaderParamName(PARAM_MADDR);
via.addParam(maddrName, inetAddress.getHostAddress());
if (inetAddress instanceof Inet4Address) {
SipHeaderParamName ttlName = new SipHeaderParamName(PARAM_TTL);
via.addParam(ttlName, IPV4_TTL);
}
}
//RFC3581
//TODO check config
via.addParam(new SipHeaderParamName(RFC3261.PARAM_RPORT), "");
buf.append(TRANSPORT_VIA_SEP2);//space
//TODO user server connection
InetAddress myAddress = config.getPublicInetAddress();
if (myAddress == null) {
myAddress = config.getLocalInetAddress();
}
buf.append(myAddress.getHostAddress()); //TODO use getHostName if real DNS
buf.append(TRANSPORT_PORT_SEP);
if (sipPort < 1) {
//use default port
if (TRANSPORT_TCP.equals(transport) || TRANSPORT_UDP.equals(transport)
|| TRANSPORT_SCTP.equals(transport)) {
sipPort = TRANSPORT_DEFAULT_PORT;
} else if (TRANSPORT_SCTP.equals(transport)) {
sipPort = TRANSPORT_TLS_PORT;
} else {
throw new RuntimeException("unknown transport type");
}
}
buf.append(sipPort);
//TODO add sent-by (p. 143) Before...
via.setValue(buf.toString());
SipTransportConnection connection = new SipTransportConnection(
config.getLocalInetAddress(), sipPort, inetAddress, port,
transport);
MessageSender messageSender = messageSenders.get(connection);
if (messageSender == null) {
messageSender = createMessageSender(connection);
}
return messageSender;
}
private String threadName(int port) {
return getClass().getSimpleName() + " " + port;
}
public void createServerTransport(String transportType, int port)
throws SocketException {
SipTransportConnection conn = new SipTransportConnection(
config.getLocalInetAddress(), port, null,
SipTransportConnection.EMPTY_PORT, transportType);
MessageReceiver messageReceiver = messageReceivers.get(conn);
if (messageReceiver == null) {
messageReceiver = createMessageReceiver(conn);
new Thread(messageReceiver, threadName(port)).start();
}
if (!messageReceiver.isListening()) {
new Thread(messageReceiver, threadName(port)).start();
}
}
public void sendResponse(SipResponse sipResponse) throws IOException {
//18.2.2
SipHeaderFieldValue topVia = Utils.getTopVia(sipResponse);
String topViaValue = topVia.getValue();
StringBuffer buf = new StringBuffer(topViaValue);
String hostport = null;
int i = topViaValue.length() - 1;
while (i > 0) {
char c = buf.charAt(i);
if (c == ' ' || c == '\t') {
hostport = buf.substring(i + 1);
break;
}
--i;
}
if (hostport == null) {
throw new RuntimeException("host or ip address not found in top via");
}
String host;
int port;
int colonPos = hostport.indexOf(RFC3261.TRANSPORT_PORT_SEP);
if (colonPos > -1) {
host = hostport.substring(0, colonPos);
port = Integer.parseInt(
hostport.substring(colonPos + 1, hostport.length()));
} else {
host = hostport;
port = RFC3261.TRANSPORT_DEFAULT_PORT;
}
String transport;
if (buf.indexOf(RFC3261.TRANSPORT_TCP) > -1) {
transport = RFC3261.TRANSPORT_TCP;
} else if (buf.indexOf(RFC3261.TRANSPORT_UDP) > -1) {
transport = RFC3261.TRANSPORT_UDP;
} else {
logger.error("no transport found in top via header," +
" discarding response");
return;
}
String received =
topVia.getParam(new SipHeaderParamName(RFC3261.PARAM_RECEIVED));
if (received != null) {
host = received;
}
//RFC3581
//TODO check config
String rport = topVia.getParam(new SipHeaderParamName(
RFC3261.PARAM_RPORT));
if (rport != null && !"".equals(rport.trim())) {
port = Integer.parseInt(rport);
}
SipTransportConnection connection;
try {
connection = new SipTransportConnection(config.getLocalInetAddress(),
sipPort, InetAddress.getByName(host),
port, transport);
} catch (UnknownHostException e) {
logger.error("unknwon host", e);
return;
}
//actual sending
//TODO manage maddr parameter in top via for multicast
if (buf.indexOf(RFC3261.TRANSPORT_TCP) > -1) {
// Socket socket = (Socket)factory.connections.get(connection);
// if (!socket.isClosed()) {
// try {
// socket.getOutputStream().write(data);
// } catch (IOException e) {
// e.printStackTrace();
// return;
// //TODO
// }
// } else {
// try {
// socket = new Socket(host, port);
// factory.connections.put(connection, socket);
// socket.getOutputStream().write(data);
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// /*
// * TODO
// * If connection attempt fails, use the procedures in RFC3263
// * for servers in order to determine the IP address and
// * port to open the connection and send the response to.
// */
// return;
// }
// }
} else {
MessageSender messageSender = messageSenders.get(connection);
if (messageSender == null) {
messageSender = createMessageSender(connection);
}
//add contact header
SipHeaderFieldName contactName = new SipHeaderFieldName(RFC3261.HDR_CONTACT);
SipHeaders respHeaders = sipResponse.getSipHeaders();
StringBuffer contactBuf = new StringBuffer();
contactBuf.append(RFC3261.LEFT_ANGLE_BRACKET);
contactBuf.append(RFC3261.SIP_SCHEME);
contactBuf.append(RFC3261.SCHEME_SEPARATOR);
contactBuf.append(messageSender.getContact());
contactBuf.append(RFC3261.RIGHT_ANGLE_BRACKET);
respHeaders.add(contactName, new SipHeaderFieldValue(contactBuf.toString()));
messageSender.sendMessage(sipResponse);
}
}
private MessageSender createMessageSender(final SipTransportConnection conn)
throws IOException {
MessageSender messageSender = null;
Object socket = null;
if (RFC3261.TRANSPORT_UDP.equalsIgnoreCase(conn.getTransport())) {
//TODO use Utils.getMyAddress to create socket on appropriate NIC
DatagramSocket datagramSocket = datagramSockets.get(conn);
if (datagramSocket == null) {
logger.debug("new DatagramSocket(" + conn.getLocalPort()
+ ", " + conn.getLocalInetAddress() + ")");
// AccessController.doPrivileged added for plugin compatibility
datagramSocket = AccessController.doPrivileged(
new PrivilegedAction() {
@Override
public DatagramSocket run() {
try {
return new DatagramSocket(conn.getLocalPort(),
conn.getLocalInetAddress());
} catch (SocketException e) {
logger.error("cannot create socket", e);
} catch (SecurityException e) {
logger.error("security exception", e);
}
return null;
}
}
);
if (datagramSocket == null) {
throw new SocketException();
}
datagramSocket.setSoTimeout(SOCKET_TIMEOUT);
datagramSockets.put(conn, datagramSocket);
logger.info("added datagram socket " + conn);
}
socket = datagramSocket;
messageSender = new UdpMessageSender(conn.getRemoteInetAddress(),
conn.getRemotePort(), datagramSocket, config, logger);
} else {
// TODO
// messageReceiver = new TcpMessageReceiver(port);
}
messageSenders.put(conn, messageSender);
//when a mesage is sent over a transport, the transport layer
//must also be able to receive messages on this transport
// MessageReceiver messageReceiver =
// createMessageReceiver(conn, socket);
MessageReceiver messageReceiver = messageReceivers.get(conn);
if (messageReceiver == null) {
messageReceiver = createMessageReceiver(conn, socket);
new Thread(messageReceiver, threadName(conn.getLocalPort())).start();
}
// if (RFC3261.TRANSPORT_UDP.equalsIgnoreCase(conn.getTransport())) {
// messageSender = new UdpMessageSender(conn.getRemoteInetAddress(),
// conn.getRemotePort(), (DatagramSocket)socket, config, logger);
// messageSenders.put(conn, messageSender);
// }
return messageSender;
}
private MessageReceiver createMessageReceiver(SipTransportConnection conn,
Object socket) throws IOException {
MessageReceiver messageReceiver = null;
if (RFC3261.TRANSPORT_UDP.equalsIgnoreCase(conn.getTransport())) {
DatagramSocket datagramSocket = (DatagramSocket)socket;
messageReceiver = new UdpMessageReceiver(datagramSocket,
transactionManager, this, config, logger);
messageReceiver.setSipServerTransportUser(sipServerTransportUser);
}
messageReceivers.put(conn, messageReceiver);
return messageReceiver;
}
private MessageReceiver createMessageReceiver(final SipTransportConnection conn)
throws SocketException {
MessageReceiver messageReceiver = null;
SipTransportConnection sipTransportConnection = conn;
if (RFC3261.TRANSPORT_UDP.equals(conn.getTransport())) {
DatagramSocket datagramSocket = datagramSockets.get(conn);
if (datagramSocket == null) {
logger.debug("new DatagramSocket(" + conn.getLocalPort()
+ ", " + conn.getLocalInetAddress());
// AccessController.doPrivileged added for plugin compatibility
datagramSocket = AccessController.doPrivileged(
new PrivilegedAction() {
@Override
public DatagramSocket run() {
try {
return new DatagramSocket(conn.getLocalPort(),
conn.getLocalInetAddress());
} catch (SocketException e) {
logger.error("cannot create socket", e);
} catch (SecurityException e) {
logger.error("security exception", e);
}
return null;
}
}
);
datagramSocket.setSoTimeout(SOCKET_TIMEOUT);
if (conn.getLocalPort() == 0) {
sipTransportConnection = new SipTransportConnection(
conn.getLocalInetAddress(),
datagramSocket.getLocalPort(),
conn.getRemoteInetAddress(),
conn.getRemotePort(),
conn.getTransport());
//config.setSipPort(datagramSocket.getLocalPort());
}
sipPort = datagramSocket.getLocalPort();
datagramSockets.put(sipTransportConnection, datagramSocket);
logger.info("added datagram socket " + sipTransportConnection);
}
messageReceiver = new UdpMessageReceiver(datagramSocket,
transactionManager, this, config, logger);
messageReceiver.setSipServerTransportUser(sipServerTransportUser);
//TODO create also tcp receiver using a recursive call
} else {
//TODO
//messageReceiver = new TcpMessageReceiver(port);
}
messageReceivers.put(sipTransportConnection, messageReceiver);
logger.info("added " + sipTransportConnection + ": " + messageReceiver
+ " to message receivers");
return messageReceiver;
}
public void setSipServerTransportUser(
SipServerTransportUser sipServerTransportUser) {
this.sipServerTransportUser = sipServerTransportUser;
}
public void closeTransports() {
for (MessageReceiver messageReceiver: messageReceivers.values()) {
messageReceiver.setListening(false);
}
for (MessageSender messageSender: messageSenders.values()) {
messageSender.stopKeepAlives();
}
try
{
Thread.sleep(SOCKET_TIMEOUT);
}
catch (InterruptedException e)
{
return;
}
// AccessController.doPrivileged added for plugin compatibility
AccessController.doPrivileged(
new PrivilegedAction() {
@Override
public Void run() {
for (DatagramSocket datagramSocket: datagramSockets.values()) {
datagramSocket.close();
}
return null;
}
}
);
datagramSockets.clear();
messageReceivers.clear();
messageSenders.clear();
}
public MessageSender getMessageSender(
SipTransportConnection sipTransportConnection) {
return messageSenders.get(sipTransportConnection);
}
public int getSipPort() {
return sipPort;
}
public void setSipPort(int sipPort) {
this.sipPort = sipPort;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy