pseudo_terminals.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * SpanDSP - a series of DSP components for telephony
  3. *
  4. * pseudo_terminals.c - pseudo terminal handling.
  5. *
  6. * Written by Steve Underwood <steveu@coppice.org>
  7. *
  8. * Copyright (C) 2012 Steve Underwood
  9. *
  10. * All rights reserved.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2, as
  14. * published by the Free Software Foundation.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24. */
  25. #include <inttypes.h>
  26. #include <stdlib.h>
  27. #if defined(WIN32)
  28. #include <windows.h>
  29. #else
  30. #if defined(__APPLE__)
  31. #include <util.h>
  32. #include <sys/ioctl.h>
  33. #elif defined(__FreeBSD__)
  34. #include <libutil.h>
  35. #include <termios.h>
  36. #else
  37. #include <pty.h>
  38. #endif
  39. #include <sys/socket.h>
  40. #include <unistd.h>
  41. #include <fcntl.h>
  42. #include <poll.h>
  43. #endif
  44. #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
  45. #include "spandsp.h"
  46. #include "pseudo_terminals.h"
  47. int next_id = 0;
  48. const char *device_root_name = "/dev/spandsp";
  49. int pseudo_terminal_close(modem_t *modem)
  50. {
  51. #if defined(WIN32)
  52. if (modem->master)
  53. {
  54. CloseHandle(modem->master);
  55. modem->master = 0;
  56. }
  57. #else
  58. if (modem->master > -1)
  59. {
  60. shutdown(modem->master, 2);
  61. close(modem->master);
  62. modem->master = -1;
  63. }
  64. #endif
  65. if (modem->slave > -1)
  66. {
  67. shutdown(modem->slave, 2);
  68. close(modem->slave);
  69. modem->slave = -1;
  70. }
  71. if (unlink(modem->devlink))
  72. return -1;
  73. return 0;
  74. }
  75. /*- End of function --------------------------------------------------------*/
  76. int pseudo_terminal_create(modem_t *modem)
  77. {
  78. #if defined(WIN32)
  79. COMMTIMEOUTS timeouts = {0};
  80. #endif
  81. memset(modem, 0, sizeof(*modem));
  82. span_log_init(&modem->logging, SPAN_LOG_NONE, NULL);
  83. span_log_set_protocol(&modem->logging, "PTY");
  84. span_log_set_level(&modem->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
  85. span_log_set_tag(&modem->logging, "PTY");
  86. modem->master = -1;
  87. modem->slave = -1;
  88. #if USE_OPENPTY
  89. if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL))
  90. {
  91. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to initialize pty\n");
  92. return -1;
  93. }
  94. modem->stty = ttyname(modem->slave);
  95. #else
  96. #if defined(WIN32)
  97. modem->slot = 4 + next_id++; /* need work here we start at COM4 for now*/
  98. snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot);
  99. modem->master = CreateFile(modem->devlink,
  100. GENERIC_READ | GENERIC_WRITE,
  101. 0,
  102. 0,
  103. OPEN_EXISTING,
  104. FILE_FLAG_OVERLAPPED,
  105. 0);
  106. if (modem->master == INVALID_HANDLE_VALUE)
  107. {
  108. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  109. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: Serial port does not exist\n");
  110. else
  111. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: Serial port open error\n");
  112. return -1;
  113. }
  114. #elif !defined(HAVE_POSIX_OPENPT)
  115. modem->master = open("/dev/ptmx", O_RDWR);
  116. #else
  117. modem->master = posix_openpt(O_RDWR | O_NOCTTY);
  118. #endif
  119. #if !defined(WIN32)
  120. if (modem->master < 0)
  121. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n");
  122. if (grantpt(modem->master) < 0)
  123. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n");
  124. if (unlockpt(modem->master) < 0)
  125. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to unlock slave pty\n");
  126. if ((modem->stty = ptsname(modem->master)) == NULL)
  127. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n");
  128. if ((modem->slave = open(modem->stty, O_RDWR)) < 0)
  129. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty);
  130. #endif
  131. #if defined(SOLARIS)
  132. ioctl(modem->slave, I_PUSH, "ptem");
  133. ioctl(modem->slave, I_PUSH, "ldterm");
  134. #endif
  135. #endif
  136. #if defined(WIN32)
  137. timeouts.ReadIntervalTimeout = 50;
  138. timeouts.ReadTotalTimeoutConstant = 50;
  139. timeouts.ReadTotalTimeoutMultiplier = 10;
  140. timeouts.WriteTotalTimeoutConstant = 50;
  141. timeouts.WriteTotalTimeoutMultiplier = 10;
  142. SetCommMask(modem->master, EV_RXCHAR);
  143. if (!SetCommTimeouts(modem->master, &timeouts))
  144. {
  145. span_log(&modem->logging, SPAN_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink);
  146. pseudo_terminal_close(modem);
  147. return -1;
  148. }
  149. modem->threadAbort = CreateEvent(NULL, true, false, NULL);
  150. #else
  151. modem->slot = next_id++;
  152. snprintf(modem->devlink, sizeof(modem->devlink), "%s/%d", device_root_name, modem->slot);
  153. /* Remove any stale link which might be present */
  154. unlink(modem->devlink);
  155. if (symlink(modem->stty, modem->devlink))
  156. {
  157. span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink);
  158. pseudo_terminal_close(modem);
  159. return -1;
  160. }
  161. if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK))
  162. {
  163. span_log(&modem->logging, SPAN_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master));
  164. pseudo_terminal_close(modem);
  165. return -1;
  166. }
  167. #endif
  168. return 0;
  169. }
  170. /*- End of function --------------------------------------------------------*/
  171. /*- End of file ------------------------------------------------------------*/