PageRenderTime 84ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/servers/media/controls/mgcp/src/main/java/org/mobicents/media/server/mgcp/tx/cmd/CreateConnectionCmd.java

http://mobicents.googlecode.com/
Java | 612 lines | 411 code | 128 blank | 73 comment | 41 complexity | 92786afc32796453a81b997b0f89ff70 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.mobicents.media.server.mgcp.tx.cmd;
  23. import java.io.IOException;
  24. import org.mobicents.media.server.mgcp.MgcpEvent;
  25. import org.mobicents.media.server.mgcp.controller.MgcpCall;
  26. import org.mobicents.media.server.mgcp.controller.MgcpConnection;
  27. import org.mobicents.media.server.mgcp.controller.MgcpEndpoint;
  28. import org.mobicents.media.server.mgcp.message.MgcpRequest;
  29. import org.mobicents.media.server.mgcp.message.MgcpResponse;
  30. import org.mobicents.media.server.mgcp.message.MgcpResponseCode;
  31. import org.mobicents.media.server.mgcp.message.Parameter;
  32. import org.mobicents.media.server.mgcp.params.LocalConnectionOptions;
  33. import org.mobicents.media.server.mgcp.tx.Action;
  34. import org.mobicents.media.server.mgcp.tx.Transaction;
  35. import org.mobicents.media.server.scheduler.Scheduler;
  36. import org.mobicents.media.server.scheduler.Task;
  37. import org.mobicents.media.server.scheduler.TaskChain;
  38. import org.mobicents.media.server.spi.ConnectionMode;
  39. import org.mobicents.media.server.spi.ConnectionType;
  40. import org.mobicents.media.server.spi.ModeNotSupportedException;
  41. import org.mobicents.media.server.utils.Text;
  42. /**
  43. *
  44. * @author kulikov
  45. */
  46. public class CreateConnectionCmd extends Action {
  47. //response strings
  48. private final static Text CALLID_MISSING = new Text("Missing call identifier");
  49. private final static Text MODE_MISSING = new Text("Missing mode value");
  50. private final static Text WILDCARD_ALL_NOT_ALLOWED= new Text("Wildcard <all> not allowed here");
  51. private final static Text SDP_NEGOTIATION_FAILED = new Text("SDP_NEGOTIATION_FAILED");
  52. private final static Text SUCCESS= new Text("Success");
  53. private Scheduler scheduler;
  54. //endpoints for searching
  55. private MgcpEndpoint[] endpoints = new MgcpEndpoint[2];
  56. //requested endpoints
  57. private MgcpEndpoint endpoint, endpoint2;
  58. private MgcpConnection[] connections = new MgcpConnection[2];
  59. //call identifier parameter
  60. private Parameter callID;
  61. //local and domain name parts of the endpoint identifier
  62. private Text localName = new Text();
  63. private Text domainName = new Text();
  64. //layout local and domain names into endpoint identifier
  65. private Text[] endpointName = new Text[]{localName, domainName};
  66. //local and domain name parts of the second endpoint identifier
  67. private Text localName2 = new Text();
  68. private Text domainName2 = new Text();
  69. //layout local and domain names into second endpoint identifier
  70. private Text[] endpointName2 = new Text[]{localName2, domainName2};
  71. //transmission mode parameter
  72. private Parameter mode;
  73. //session descriptor parameter
  74. private Parameter sdp;
  75. private TaskChain handler;
  76. private Preprocessor preprocessor;
  77. private MgcpRequest request;
  78. //subtasks
  79. private EndpointLocator endpointLocator;
  80. private SecondEndpointLocator secondEndpointLocator;
  81. private RtpConnectionCreator rtpCreator;
  82. private RtpConnector rtpConnector;
  83. private RtpTransmittor rtpTransmittor;
  84. private LocalConnector localConnector;
  85. private LocalTransmittor localTransmittor;
  86. private Responder responder;
  87. private ErrorHandle errorHandle;
  88. private MgcpCall call;
  89. //error code and message
  90. private int code;
  91. private Text message;
  92. //local connection options
  93. private LocalConnectionOptions lcOptions = new LocalConnectionOptions();
  94. /**
  95. * Creates new instance of this action executor.
  96. *
  97. * @param scheduler the job scheduler.
  98. */
  99. public CreateConnectionCmd(Scheduler scheduler) {
  100. this.scheduler = scheduler;
  101. handler = new TaskChain(6);
  102. //intialize action's subtasks
  103. endpointLocator = new EndpointLocator(scheduler);
  104. secondEndpointLocator = new SecondEndpointLocator(scheduler);
  105. rtpCreator = new RtpConnectionCreator(scheduler);
  106. rtpConnector = new RtpConnector(scheduler);
  107. rtpTransmittor = new RtpTransmittor(scheduler);
  108. localConnector = new LocalConnector(scheduler);
  109. localTransmittor = new LocalTransmittor(scheduler);
  110. responder = new Responder(scheduler);
  111. errorHandle = new ErrorHandle(scheduler);
  112. preprocessor = new Preprocessor(scheduler);
  113. handler.add(preprocessor, 1000000L);
  114. this.setActionHandler(handler);
  115. this.setRollbackHandler(errorHandle);
  116. }
  117. @Override
  118. public void start(Transaction tx) {
  119. handler.clean();
  120. handler.add(preprocessor, 1000000L);
  121. super.start(tx);
  122. }
  123. /**
  124. * Preprocesses MGCP create connection message and dynamically constructs
  125. * task chain.
  126. */
  127. private class Preprocessor extends Task {
  128. public Preprocessor(Scheduler scheduler) {
  129. super(scheduler);
  130. }
  131. @Override
  132. public long getPriority() {
  133. return 0;
  134. }
  135. @Override
  136. public long getDuration() {
  137. return 0;
  138. }
  139. @Override
  140. public long perform() {
  141. endpoint = null;
  142. endpoint2 = null;
  143. request = (MgcpRequest) getEvent().getMessage();
  144. Parameter z2 = request.getParameter(Parameter.SECOND_ENDPOINT);
  145. sdp = request.getParameter(Parameter.SDP);
  146. //second endpoint and sdp should not be all together in one message
  147. if (z2 != null && sdp != null) {
  148. throw new MgcpCommandException(MgcpResponseCode.PROTOCOL_ERROR, new Text("Second endpoint and remote SDP present in message"));
  149. }
  150. //getting call identifier
  151. callID = request.getParameter(Parameter.CALL_ID);
  152. if (callID == null) {
  153. throw new MgcpCommandException(MgcpResponseCode.PROTOCOL_ERROR, CALLID_MISSING);
  154. }
  155. //getting transmission mode
  156. mode = request.getParameter(Parameter.MODE);
  157. if (mode == null) {
  158. throw new MgcpCommandException(MgcpResponseCode.PROTOCOL_ERROR, MODE_MISSING);
  159. }
  160. //getting endpoint name
  161. request.getEndpoint().divide('@', endpointName);
  162. //checking the local name:
  163. if (localName.contains('*')) {
  164. throw new MgcpCommandException(MgcpResponseCode.WILDCARD_TOO_COMPLICATED, WILDCARD_ALL_NOT_ALLOWED);
  165. }
  166. if (z2 != null) {
  167. z2.getValue().divide('@', endpointName2);
  168. //checking the local name 2
  169. if (localName2.contains('*')) {
  170. throw new MgcpCommandException(MgcpResponseCode.WILDCARD_TOO_COMPLICATED, new Text("Wildcard all is not allowed here"));
  171. }
  172. }
  173. //modify local connection options
  174. Parameter l = request.getParameter(Parameter.LOCAL_CONNECTION_OPTIONS);
  175. if (l != null) {
  176. lcOptions.setValue(l.getValue());
  177. } else {
  178. lcOptions.setValue(null);
  179. }
  180. call = transaction().getCall(callID.getValue(), true);
  181. if (z2 != null) {
  182. //create two local connections
  183. handler.add(endpointLocator, 5000000L);
  184. handler.add(secondEndpointLocator, 5000000L);
  185. handler.add(localConnector, 5000000L);
  186. handler.add(localTransmittor, 5000000L);
  187. handler.add(responder, 5000000L);
  188. } else {
  189. //create one RTP connection
  190. handler.add(endpointLocator, 5000000L);
  191. handler.add(rtpCreator, 5000000L);
  192. handler.add(rtpConnector, 5000000L);
  193. handler.add(rtpTransmittor, 5000000L);
  194. handler.add(responder, 5000000L);
  195. }
  196. return 0;
  197. }
  198. }
  199. /**
  200. * Searches endpoint specified in message.
  201. *
  202. * The result will be stored into variable endpoint.
  203. */
  204. private class EndpointLocator extends Task {
  205. public EndpointLocator(Scheduler scheduler) {
  206. super(scheduler);
  207. }
  208. @Override
  209. public long getPriority() {
  210. return 0;
  211. }
  212. @Override
  213. public long getDuration() {
  214. return 0;
  215. }
  216. @Override
  217. public long perform() {
  218. try {
  219. //searching endpoint
  220. int n = transaction().find(localName, endpoints);
  221. if (n == 0) {
  222. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Endpoint not available"));
  223. }
  224. //extract found endpoint
  225. endpoint = endpoints[0];
  226. } catch (Exception e) {
  227. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Endpoint not available"));
  228. }
  229. return 0;
  230. }
  231. }
  232. private class SecondEndpointLocator extends Task {
  233. public SecondEndpointLocator(Scheduler scheduler) {
  234. super(scheduler);
  235. }
  236. @Override
  237. public long getPriority() {
  238. return 0;
  239. }
  240. @Override
  241. public long getDuration() {
  242. return 0;
  243. }
  244. @Override
  245. public long perform() {
  246. try {
  247. //searching endpoint
  248. int n = transaction().find(localName2, endpoints);
  249. if (n == 0) {
  250. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Endpoint not available"));
  251. }
  252. //extract found endpoint
  253. endpoint2 = endpoints[0];
  254. } catch (Exception e) {
  255. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Endpoint not available"));
  256. }
  257. return 0;
  258. }
  259. }
  260. private class RtpConnectionCreator extends Task {
  261. public RtpConnectionCreator(Scheduler scheduler) {
  262. super(scheduler);
  263. }
  264. @Override
  265. public long getPriority() {
  266. return 0;
  267. }
  268. @Override
  269. public long getDuration() {
  270. return 0;
  271. }
  272. @Override
  273. public long perform() {
  274. try {
  275. connections[0] = endpoint.createConnection(call, ConnectionType.RTP);
  276. } catch (Exception e) {
  277. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Problem with connection" + e.getMessage()));
  278. }
  279. return 0;
  280. }
  281. }
  282. private class RtpConnector extends Task {
  283. public RtpConnector(Scheduler scheduler) {
  284. super(scheduler);
  285. }
  286. @Override
  287. public long getPriority() {
  288. return 0;
  289. }
  290. @Override
  291. public long getDuration() {
  292. return 0;
  293. }
  294. @Override
  295. public long perform() {
  296. if (sdp != null) {
  297. try {
  298. connections[0].setOtherParty(sdp.getValue());
  299. } catch (IOException e) {
  300. throw new MgcpCommandException(MgcpResponseCode.MISSING_REMOTE_CONNECTION_DESCRIPTOR, SDP_NEGOTIATION_FAILED);
  301. }
  302. }
  303. return 0;
  304. }
  305. }
  306. private class RtpTransmittor extends Task {
  307. public RtpTransmittor(Scheduler scheduler) {
  308. super(scheduler);
  309. }
  310. @Override
  311. public long getPriority() {
  312. return 0;
  313. }
  314. @Override
  315. public long getDuration() {
  316. return 0;
  317. }
  318. @Override
  319. public long perform() {
  320. try {
  321. connections[0].setMode(mode.getValue());
  322. } catch (ModeNotSupportedException e) {
  323. throw new MgcpCommandException(MgcpResponseCode.INVALID_OR_UNSUPPORTED_MODE, new Text("Not supported mode"));
  324. }
  325. connections[0].setGain(lcOptions.getGain());
  326. return 0;
  327. }
  328. }
  329. private class LocalConnector extends Task {
  330. public LocalConnector(Scheduler scheduler) {
  331. super(scheduler);
  332. }
  333. @Override
  334. public long getPriority() {
  335. return 0;
  336. }
  337. @Override
  338. public long getDuration() {
  339. return 0;
  340. }
  341. @Override
  342. public long perform() {
  343. try {
  344. connections[0] = endpoint.createConnection(call, ConnectionType.LOCAL);
  345. } catch (Exception e) {
  346. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Problem with connection"));
  347. }
  348. try {
  349. connections[1] = endpoint2.createConnection(call, ConnectionType.LOCAL);
  350. } catch (Exception e) {
  351. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Problem with connection"));
  352. }
  353. try {
  354. connections[0].setOtherParty(connections[1]);
  355. } catch (Exception e) {
  356. throw new MgcpCommandException(MgcpResponseCode.ENDPOINT_NOT_AVAILABLE, new Text("Problem with joining"));
  357. }
  358. if (mode == null) {
  359. throw new MgcpCommandException(MgcpResponseCode.PROTOCOL_ERROR, new Text("Mode was not specified"));
  360. }
  361. return 0;
  362. }
  363. }
  364. private class LocalTransmittor extends Task {
  365. public LocalTransmittor(Scheduler scheduler) {
  366. super(scheduler);
  367. }
  368. @Override
  369. public long getPriority() {
  370. return 0;
  371. }
  372. @Override
  373. public long getDuration() {
  374. return 0;
  375. }
  376. @Override
  377. public long perform() {
  378. ConnectionMode m = ConnectionMode.valueOf(mode.getValue());
  379. try {
  380. connections[0].setMode(m);
  381. connections[1].setMode(ConnectionMode.SEND_RECV);
  382. } catch (Exception e) {
  383. throw new MgcpCommandException(MgcpResponseCode.INVALID_OR_UNSUPPORTED_MODE, new Text("Unsupported mode"));
  384. }
  385. connections[0].setGain(lcOptions.getGain());
  386. return 0;
  387. }
  388. }
  389. private class Responder extends Task {
  390. public Responder(Scheduler scheduler) {
  391. super(scheduler);
  392. }
  393. @Override
  394. public long getPriority() {
  395. return 0;
  396. }
  397. @Override
  398. public long getDuration() {
  399. return 0;
  400. }
  401. @Override
  402. public long perform() {
  403. MgcpEvent evt = transaction().getProvider().createEvent(MgcpEvent.RESPONSE, getEvent().getAddress());
  404. try {
  405. MgcpResponse response = (MgcpResponse) evt.getMessage();
  406. response.setResponseCode(MgcpResponseCode.TRANSACTION_WAS_EXECUTED);
  407. response.setResponseString(SUCCESS);
  408. //set parameters
  409. response.setParameter(Parameter.CONNECTION_ID, connections[0].getID());
  410. response.setParameter(Parameter.ENDPOINT_ID, endpoint.getFullName());
  411. if (endpoint2 == null) {
  412. response.setParameter(Parameter.SDP, connections[0].getDescriptor());
  413. }
  414. response.setTxID(transaction().getId());
  415. if (endpoint2 != null) {
  416. response.setParameter(Parameter.SECOND_ENDPOINT, endpoint2.getFullName());
  417. }
  418. if (connections[1] != null) {
  419. response.setParameter(Parameter.CONNECTION_ID2, connections[1].getID());
  420. }
  421. transaction().getProvider().send(evt);
  422. } catch (IOException e) {
  423. } finally {
  424. evt.recycle();
  425. }
  426. return 0;
  427. }
  428. }
  429. private class ErrorHandle extends Task {
  430. public ErrorHandle(Scheduler scheduler) {
  431. super(scheduler);
  432. }
  433. @Override
  434. public long getPriority() {
  435. return 0;
  436. }
  437. @Override
  438. public long getDuration() {
  439. return 0;
  440. }
  441. @Override
  442. public long perform() {
  443. if (endpoint != null) {
  444. endpoint.share();
  445. if (connections[0] != null) {
  446. endpoint.deleteConnection(connections[0].getID());
  447. }
  448. }
  449. if (endpoint2 != null) {
  450. endpoint2.share();
  451. if (connections[1] != null) {
  452. endpoint2.deleteConnection(connections[1].getID());
  453. }
  454. }
  455. code = ((MgcpCommandException)transaction().getLastError()).getCode();
  456. message = ((MgcpCommandException)transaction().getLastError()).getErrorMessage();
  457. MgcpEvent evt = transaction().getProvider().createEvent(MgcpEvent.RESPONSE, getEvent().getAddress());
  458. try {
  459. MgcpResponse response = (MgcpResponse) evt.getMessage();
  460. response.setResponseCode(code);
  461. response.setResponseString(message);
  462. response.setTxID(transaction().getId());
  463. transaction().getProvider().send(evt);
  464. } catch (IOException e) {
  465. } finally {
  466. evt.recycle();
  467. }
  468. return 0;
  469. }
  470. }
  471. /**
  472. * Converts mode in case of unidirectional transmission.
  473. *
  474. * @param mode the original mode value
  475. * @return mode with opposite transmission mode.
  476. */
  477. private ConnectionMode invert(ConnectionMode mode) {
  478. switch (mode) {
  479. case SEND_ONLY : return ConnectionMode.RECV_ONLY;
  480. case RECV_ONLY : return ConnectionMode.SEND_ONLY;
  481. default : return mode;
  482. }
  483. }
  484. }