freeswitch/libs/spandsp/tests/pseudo_terminals.c

202 lines
5.9 KiB
C

/*
* SpanDSP - a series of DSP components for telephony
*
* pseudo_terminals.c - pseudo terminal handling.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2012 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <inttypes.h>
#include <stdlib.h>
#if defined(WIN32)
#include <windows.h>
#else
#if defined(__APPLE__)
#include <util.h>
#include <sys/ioctl.h>
#elif defined(__FreeBSD__)
#include <libutil.h>
#include <termios.h>
#else
#include <pty.h>
#endif
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#endif
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
#include "spandsp.h"
#include "pseudo_terminals.h"
int next_id = 0;
const char *device_root_name = "/dev/spandsp";
int pseudo_terminal_close(modem_t *modem)
{
#if defined(WIN32)
if (modem->master)
{
CloseHandle(modem->master);
modem->master = 0;
}
#else
if (modem->master > -1)
{
shutdown(modem->master, 2);
close(modem->master);
modem->master = -1;
}
#endif
if (modem->slave > -1)
{
shutdown(modem->slave, 2);
close(modem->slave);
modem->slave = -1;
}
if (unlink(modem->devlink))
return -1;
return 0;
}
/*- End of function --------------------------------------------------------*/
int pseudo_terminal_create(modem_t *modem)
{
#if defined(WIN32)
COMMTIMEOUTS timeouts = {0};
#endif
memset(modem, 0, sizeof(*modem));
span_log_init(&modem->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&modem->logging, "PTY");
span_log_set_level(&modem->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
span_log_set_tag(&modem->logging, "PTY");
modem->master = -1;
modem->slave = -1;
#if USE_OPENPTY
if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL))
{
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to initialize pty\n");
return -1;
}
modem->stty = ttyname(modem->slave);
#else
#if defined(WIN32)
modem->slot = 4 + next_id++; /* Need work here. We start at COM4 for now */
snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot);
modem->master = CreateFile(modem->devlink,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if (modem->master == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: Serial port does not exist\n");
else
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: Serial port open error\n");
return -1;
}
#elif !defined(HAVE_POSIX_OPENPT)
modem->master = open("/dev/ptmx", O_RDWR);
#else
modem->master = posix_openpt(O_RDWR | O_NOCTTY);
#endif
#if !defined(WIN32)
if (modem->master < 0)
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n");
if (grantpt(modem->master) < 0)
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n");
if (unlockpt(modem->master) < 0)
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to unlock slave pty\n");
if ((modem->stty = ptsname(modem->master)) == NULL)
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n");
if ((modem->slave = open(modem->stty, O_RDWR)) < 0)
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty);
#endif
#if defined(SOLARIS)
ioctl(modem->slave, I_PUSH, "ptem");
ioctl(modem->slave, I_PUSH, "ldterm");
#endif
#endif
#if defined(WIN32)
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
SetCommMask(modem->master, EV_RXCHAR);
if (!SetCommTimeouts(modem->master, &timeouts))
{
span_log(&modem->logging, SPAN_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink);
pseudo_terminal_close(modem);
return -1;
}
modem->threadAbort = CreateEvent(NULL, true, false, NULL);
#else
modem->slot = next_id++;
snprintf(modem->devlink, sizeof(modem->devlink), "%s/%d", device_root_name, modem->slot);
/* Remove any stale link which might be present */
unlink(modem->devlink);
if (symlink(modem->stty, modem->devlink))
{
span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink);
pseudo_terminal_close(modem);
return -1;
}
if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK))
{
span_log(&modem->logging, SPAN_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master));
pseudo_terminal_close(modem);
return -1;
}
#endif
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/