|
modemu2k 0.2.3
Library that provides telnet capability to a comm program
|
GitHub repository |
Public API for the modemu2k PTY-based modem emulator library. More...
#include <poll.h>#include <stddef.h>#include "modemu2k_version.h"Go to the source code of this file.
Macros | |
| #define | M2K_API |
| Public-symbol visibility/export marker. | |
| #define | M2K_DEPRECATED(msg) |
| #define | M2K_ERROR_BUFFER_SIZE 256 |
| #define | M2K_MAX_POLLFDS 3 |
Typedefs | |
| typedef struct m2k_s | m2k_t |
| Opaque modem emulator context. Create with m2k_new(), destroy with m2k_free(). | |
| typedef void(* | m2k_log_fn) (const char *msg, void *userdata) |
| Log callback type. | |
Enumerations | |
| enum | m2k_err_t { M2K_OK = 0 , M2K_ERR_NOMEM , M2K_ERR_PTY , M2K_ERR_SOCKET , M2K_ERR_TIMEOUT , M2K_ERR_CANCELED , M2K_ERR_BUG , M2K_ERR_WOULDBLOCK , M2K_ERR_AT } |
| Return codes used by all m2k_* functions. More... | |
Functions | |
| M2K_API const char * | m2k_version (void) |
| Runtime version string of the linked libmodemu2k. | |
| M2K_API m2k_t * | m2k_new (void) |
| Allocate and initialise a new modem context. | |
| M2K_API void | m2k_free (m2k_t *ctx) |
Release all resources held by ctx. | |
| M2K_API void | m2k_set_log_fn (m2k_t *ctx, m2k_log_fn fn, void *userdata) |
| Install a log callback. | |
| M2K_API void | m2k_set_error_buffer (m2k_t *ctx, char *buf, size_t size) |
| Install a buffer that receives a detailed message for the most recent error. | |
| M2K_API m2k_err_t | m2k_atcmd (m2k_t *ctx, const char *cmd) |
| Feed a Hayes AT command string to the modem. | |
| M2K_API | M2K_DEPRECATED ("use m2k_run() or the step API instead") m2k_err_t m2k_dial(m2k_t *ctx |
Open a TCP connection to host : port. | |
| M2K_API m2k_err_t | m2k_hangup (m2k_t *ctx) |
| Tear down the active TCP connection. | |
| M2K_API m2k_err_t | m2k_escape (m2k_t *ctx) |
| Request an immediate return to command mode from online mode. | |
| M2K_API const char * | m2k_strerror (m2k_err_t err) |
Return a human-readable string for err. | |
| M2K_API m2k_err_t | m2k_setup_stdin (m2k_t *ctx) |
| Use stdin/stdout as the TTY (standalone mode). | |
| M2K_API m2k_err_t | m2k_setup_pty (m2k_t *ctx, const char **slave_out) |
| Allocate a PTY master and return the slave device path. | |
| M2K_API m2k_err_t | m2k_setup_comm_program (m2k_t *ctx, const char *cmd) |
| Allocate a PTY and fork/exec a comm program on the slave. | |
| M2K_API m2k_err_t | m2k_setup_dev (m2k_t *ctx, const char *dev) |
| Open an existing PTY device as the TTY. | |
| M2K_API m2k_err_t | m2k_setup_listen (m2k_t *ctx, const char *port) |
Bind a TCP listening socket on port. | |
| M2K_API m2k_err_t | m2k_setup_app_io (m2k_t *ctx) |
| Embed mode: no real TTY fd; the host application supplies the bytes a TTY would normally produce, via m2k_write_from_app(), and consumes the bytes modemu2k would normally send to the TTY, via m2k_read_to_app(). | |
| M2K_API m2k_err_t | m2k_write_from_app (m2k_t *ctx, const void *buf, size_t len, size_t *consumed) |
| Push bytes into the modem as if they had been read from the TTY. | |
| M2K_API m2k_err_t | m2k_read_to_app (m2k_t *ctx, void *buf, size_t max, size_t *len_out) |
| Drain bytes from the modem that would normally have been written to the TTY. | |
| M2K_API int | m2k_has_pending_output (const m2k_t *ctx) |
| Test whether the modem has TTY-bound bytes still buffered. | |
| M2K_API int | m2k_get_listen_fd (const m2k_t *ctx) |
| Expose the listening socket's fd (after m2k_setup_listen, before m2k_listen_accept). | |
| M2K_API m2k_err_t | m2k_listen_accept (m2k_t *ctx) |
| Accept a single incoming connection on the listening socket opened by m2k_setup_listen() and adopt it as the TTY. | |
| M2K_API m2k_err_t | m2k_run (m2k_t *ctx) |
| Run the modem command/online loop until the PTY closes. | |
| M2K_API m2k_err_t | m2k_get_pollfds (m2k_t *ctx, struct pollfd *fds, size_t *nfds_inout, int *timeout_ms) |
| Describe the fds and timeout the caller's event loop should watch. | |
| M2K_API m2k_err_t | m2k_step (m2k_t *ctx, struct pollfd *fds, size_t nfds) |
| Run one non-blocking iteration of the state machine. | |
| M2K_API int | m2k_run_done (const m2k_t *ctx) |
| Test whether the session has ended. | |
| M2K_API int | m2k_is_online (const m2k_t *ctx) |
| Test whether the modem is currently in online mode. | |
| M2K_API int | m2k_has_carrier (const m2k_t *ctx) |
| Test whether the modem has an active carrier (live TCP socket). | |
| M2K_API void | m2k_set_dtr (m2k_t *ctx, int on) |
| Set the host's DTR (Data Terminal Ready) signal state. | |
| M2K_API void | m2k_set_rts (m2k_t *ctx, int on) |
| Set the host's RTS (Request to Send) signal state. | |
| M2K_API int | m2k_get_dtr (const m2k_t *ctx) |
| M2K_API int | m2k_get_rts (const m2k_t *ctx) |
| M2K_API void | m2k_set_force_verbose (m2k_t *ctx, int on) |
| Bypass the ATV verbose mask in verboseOut() / verbosePerror(). | |
| M2K_API int | m2k_get_force_verbose (const m2k_t *ctx) |
Variables | |
| M2K_API const char * | host |
| M2K_API const char const char * | port |
Public API for the modemu2k PTY-based modem emulator library.
The pattern used by the bundled modemu2k executable (see src/main.c) shows the recommended way to use the library:
For finer control — driving the state machine yourself rather than letting m2k_run() block — replace m2k_run() with a poll loop built around m2k_get_pollfds() + m2k_step(), exiting when m2k_run_done() returns nonzero. Dialing from code is done by feeding the ATD string through the CMD-mode line buffer (write to the TTY in standalone mode, or m2k_write_from_app() in embed mode); m2k_step() then walks the DIAL → ONLINE transition. m2k_escape() and m2k_hangup() drive the online→cmd and disconnect transitions programmatically.
| #define M2K_API |
Public-symbol visibility/export marker.
On platforms where it matters (Windows DLLs, ELF builds with -fvisibility=hidden) this macro decorates every documented public function below. Defaults to nothing on Unix-default builds, where symbols are visible already. Define M2K_BUILDING_DLL before including this header inside the modemu2k source tree on Windows to flip the dllimport/dllexport direction; consumers leave it undefined.
Borrowed from libuv (UV_EXTERN) / libcurl (CURL_EXTERN) / libssh2 (LIBSSH2_API).
| #define M2K_ERROR_BUFFER_SIZE 256 |
Recommended minimum size for the m2k_set_error_buffer() buffer.
| #define M2K_MAX_POLLFDS 3 |
Maximum number of pollfds modemu2k will ever ask the caller to watch.
| typedef void(* m2k_log_fn) (const char *msg, void *userdata) |
Log callback type.
| msg | NUL-terminated log message. |
| userdata | Caller-supplied pointer passed unchanged from m2k_set_log_fn(). |
| enum m2k_err_t |
Return codes used by all m2k_* functions.
| Enumerator | |
|---|---|
| M2K_OK | Success. |
| M2K_ERR_NOMEM | Memory allocation failed. |
| M2K_ERR_PTY | PTY open or allocation failed. |
| M2K_ERR_SOCKET | TCP connect or I/O error. |
| M2K_ERR_TIMEOUT | Operation timed out. |
| M2K_ERR_CANCELED | Operation canceled (e.g., +++ escape sequence). |
| M2K_ERR_BUG | Internal assertion failure — should not happen. |
| M2K_ERR_WOULDBLOCK | Operation would block; call m2k_step() (or wait for the relevant fd to become ready) and retry. Mirrors libssh2's LIBSSH2_ERROR_EAGAIN. |
| M2K_ERR_AT | AT command rejected by the lexer (malformed input). |
Feed a Hayes AT command string to the modem.
Intended for one-shot configuration commands (S-register sets, mode toggles, etc.). Action commands like ATD/ATO are recognised by the lexer but do not drive a connection from this entry point; use m2k_dial() / m2k_online() for those.
| ctx | Modem context. |
| cmd | NUL-terminated AT command (e.g. "ATZ" or "ATS0=1"). A string with no AT prefix is silently ignored. |
AT prefix); M2K_ERR_AT if the lexer rejected the command as malformed, or if the command was an action verb (ATD or ATO) — those drive a connection and so are not actionable from this one-shot configuration entry. To dial or resume online mode from code, feed the ATD/ATO string through the CMD-mode line buffer (m2k_write_from_app() in embed mode, or just write to the TTY in standalone mode) and let m2k_step() dispatch it. M2K_ERR_BUG only for unexpected lexer states.Open a TCP connection to host : port.
Enter online mode and relay data between the PTY and the socket.
Transitions the modem from idle to connected state. Call m2k_online() after this to start relaying data.
| ctx | Modem context. |
| host | Hostname or numeric IP address. |
| port | Service name or decimal port number. |
Blocks until the connection closes or the +++ escape sequence is detected. Returns M2K_ERR_CANCELED when the caller escapes back to command mode.
| ctx | Modem context (must have an active connection from m2k_dial()). |
Request an immediate return to command mode from online mode.
Drives the same transition that the +++ escape sequence would — but without the silence-guard timing or sending the literal +++ bytes through the I/O path. Useful from a host application that embeds modemu2k and wants programmatic control of the mode.
The transition takes effect on the next m2k_step() / m2k_run() iteration. The underlying TCP connection is left intact; use m2k_hangup() afterward if you also want to drop it.
A no-op when the context is not currently in online mode.
| ctx | Modem context. |
Release all resources held by ctx.
| ctx | Context to destroy. Safe to call with NULL. |
Return the most recent value passed to m2k_set_dtr() (1 by default).
Return the most recent value passed to m2k_set_force_verbose() (0 by default).
Expose the listening socket's fd (after m2k_setup_listen, before m2k_listen_accept).
Lets a host event loop poll the fd for POLLIN — i.e. detect an incoming TCP connection (the "RING" event in modem terms) so it can call m2k_listen_accept() at the right moment instead of blocking unconditionally on it.
| ctx | Modem context. |
| M2K_API m2k_err_t m2k_get_pollfds | ( | m2k_t * | ctx, |
| struct pollfd * | fds, | ||
| size_t * | nfds_inout, | ||
| int * | timeout_ms ) |
Describe the fds and timeout the caller's event loop should watch.
Fills fds with the fds modemu2k currently wants to monitor and stores the longest acceptable wait in *timeout_ms (-1 = wait indefinitely, 0 = poll immediately). Each pollfd's .fd and .events are set; the caller is responsible for the .revents field after calling poll().
| ctx | Modem context. |
| fds | Caller-provided array of at least M2K_MAX_POLLFDS entries. |
| nfds_inout | In: capacity of fds (must be >= M2K_MAX_POLLFDS). Out: number of entries actually populated. Zero means the session is done; the caller should exit the loop. |
| timeout_ms | Out: maximum wait in milliseconds before m2k_step() needs to be called again. -1 means no deadline. |
*nfds_inout is too small. Return the most recent value passed to m2k_set_rts() (1 by default).
Tear down the active TCP connection.
| ctx | Modem context. |
Test whether the modem has an active carrier (live TCP socket).
Maps to the DCD (Data Carrier Detect) signal real serial modems expose. Stays true after a +++ escape back to command mode as long as the TCP connection is still up; goes false on hangup, NO CARRIER, or before the first dial.
| ctx | Modem context. |
Test whether the modem has TTY-bound bytes still buffered.
Returns nonzero whenever a subsequent m2k_read_to_app() would deliver at least one byte without first needing another m2k_step()/poll cycle. See m2k_read_to_app() for the back-pressure pattern this predicate exists to support.
Always returns 0 when the context isn't in app-I/O mode.
| ctx | Modem context. |
Test whether the modem is currently in online mode.
Useful for embed-mode hosts that paint mode-specific UI (status bar, local echo toggle, etc.) and need to know whether m2k is relaying bytes to/from a connected socket vs. consuming AT commands.
| ctx | Modem context. |
Accept a single incoming connection on the listening socket opened by m2k_setup_listen() and adopt it as the TTY.
Blocks until a client connects. The listening socket is closed once a connection is accepted (modemu2k handles one client per session). Call before m2k_run().
| ctx | Modem context (must have an active listener from m2k_setup_listen()). |
Allocate and initialise a new modem context.
Drain bytes from the modem that would normally have been written to the TTY.
Only valid after m2k_setup_app_io(). Copies up to max bytes from the internal TTY write buffer into buf and stores the actual length in *len_out (which may be zero if there is nothing pending).
Skipping this collapses throughput to roughly "your buffer size per poll timeout."
| ctx | Modem context. |
| buf | Destination buffer. Must be non-NULL when max > 0. |
| max | Maximum bytes to copy. May be 0. |
| len_out | Out: number of bytes actually copied (0 means no data). Must be non-NULL. |
Run the modem command/online loop until the PTY closes.
Handles the full state machine: reads Hayes AT commands in command mode, dials on ATD, relays data in online mode, and returns to command mode on +++ escape or disconnection. Call one of the m2k_setup_*() functions before calling m2k_run().
Equivalent to:
| ctx | Modem context. |
Test whether the session has ended.
| ctx | Modem context. |
Set the host's DTR (Data Terminal Ready) signal state.
On the 1→0 transition while a connection is live, modemu2k hangs the connection up — matching the typical real-modem AT&D2 default of "DTR drop terminates the call". Drop is otherwise a no-op (no carrier to drop). The DTR &D register is not (yet) lexable from AT command strings, so this function is the sole way to drive DTR-related behavior. Default state is asserted (1).
| ctx | Modem context. |
| on | Non-zero to assert DTR, zero to drop it. |
Install a buffer that receives a detailed message for the most recent error.
When buf is non-NULL, internal error paths write a human-readable, contextual message into buf (NUL-terminated, truncated to fit) in addition to any logging via m2k_set_log_fn(). The caller can then present the message after a function returns a non-OK m2k_err_t — curl-style CURLOPT_ERRORBUFFER semantics.
The buffer is only updated when an error actually occurs; successful calls leave it untouched, so callers should check the function's return code first.
| ctx | Modem context. |
| buf | Caller-owned buffer that outlives the context, or NULL to detach. Recommended size: M2K_ERROR_BUFFER_SIZE. |
| size | Capacity of buf in bytes (including the trailing NUL). Ignored when buf is NULL. Passing size = 0 with a non-NULL buf is equivalent to detaching — the pointer is stored but never written through. |
Bypass the ATV verbose mask in verboseOut() / verbosePerror().
Normally narration sites are gated by ctx->atcmd.pv & mask, which the Hayes ATV command sets. ATZ resets atcmd.pv to its NV default of 0 (via the atcmdNV copy inside atcmdZ), so a host that wanted log output for the whole run can be silenced by any user-issued ATZ. This flag is OR'd into the gate, so log output survives regardless of the ATV mask. Default is off. Used by the standalone CLI's -v flag.
| ctx | Modem context. |
| on | Non-zero to force narration on, zero to defer to ATV. |
| M2K_API void m2k_set_log_fn | ( | m2k_t * | ctx, |
| m2k_log_fn | fn, | ||
| void * | userdata ) |
Install a log callback.
When fn is non-NULL, all diagnostic messages are routed to it instead of stderr. Pass fn = NULL to restore the default stderr output.
| ctx | Modem context. |
| fn | Callback to receive log messages, or NULL. |
| userdata | Opaque pointer forwarded to every fn invocation. |
Set the host's RTS (Request to Send) signal state.
Tracked for symmetry with real Hayes modems; modemu2k does not act on RTS state (hardware flow control is meaningless for a TCP-based virtual modem — the kernel's socket buffers and TCP windowing do that job). Default state is asserted (1).
| ctx | Modem context. |
| on | Non-zero to assert RTS, zero to drop it. |
Embed mode: no real TTY fd; the host application supplies the bytes a TTY would normally produce, via m2k_write_from_app(), and consumes the bytes modemu2k would normally send to the TTY, via m2k_read_to_app().
Intended for embedding modemu2k inside a host program that already owns the terminal/serial interface (e.g. a comm program linking libmodemu2k instead of forking the standalone binary). The socket side still uses real fds and integrates with the host's event loop via m2k_get_pollfds() as usual.
| ctx | Modem context. |
Allocate a PTY and fork/exec a comm program on the slave.
The slave device path is substituted for s in cmd. Call before m2k_run().
| ctx | Modem context. |
| cmd | Shell command; s is replaced by the slave device path. |
Open an existing PTY device as the TTY.
| ctx | Modem context. |
| dev | Path to the PTY master device (e.g. "/dev/ptyp0"). |
Bind a TCP listening socket on port.
Binds and listens on all interfaces (dual-stack IPv4/IPv6); returns immediately without waiting for a connection. Pair with m2k_listen_accept() to accept one connection and use it as the TTY, or integrate the listener fd with the caller's own event loop.
Suitable for use as a virtual-modem backend for programs that connect to modemu2k over TCP, such as dosemu2.
| ctx | Modem context. |
| port | Service name or decimal port number to listen on. |
Allocate a PTY master and return the slave device path.
The returned pointer is owned by the context — do NOT free() it. It remains valid until the next m2k_setup_*() call or m2k_free(ctx).
Use this when you need the slave path itself (e.g. to print it with –show). To fork a comm program on the slave, prefer m2k_setup_comm_program().
| ctx | Modem context. |
| slave_out | Out: pointer to a NUL-terminated slave path inside ctx. Must be non-NULL. |
Run one non-blocking iteration of the state machine.
Consumes the events the caller's poll() reported (via the .revents fields of fds) and advances the cmd-mode / online-mode state once. Does no poll() of its own. Safe to call with all .revents == 0 (the call is then a no-op).
| ctx | Modem context. |
| fds | The pollfd array previously filled by m2k_get_pollfds(), with the OS's .revents values populated by the caller. |
| nfds | Number of entries in fds (the value m2k_get_pollfds returned in *nfds_inout). |
Return a human-readable string for err.
| err | Error code. |
| M2K_API const char * m2k_version | ( | void | ) |
Runtime version string of the linked libmodemu2k.
Lets a caller detect a header/library version mismatch by comparing M2K_VERSION (the value at the time the caller's translation unit was compiled) against m2k_version() (the value the linked library was built with).
| M2K_API m2k_err_t m2k_write_from_app | ( | m2k_t * | ctx, |
| const void * | buf, | ||
| size_t | len, | ||
| size_t * | consumed ) |
Push bytes into the modem as if they had been read from the TTY.
Only valid after m2k_setup_app_io(). Accepts as many bytes from buf as the internal TTY read buffer has room for (partial accept; the actual count is returned via *consumed). The accepted bytes are processed by the next m2k_step() call.
If the buffer is completely full, *consumed is set to 0 and the function returns M2K_ERR_WOULDBLOCK — call m2k_step() to drain, then retry.
| ctx | Modem context. |
| buf | Bytes to inject. Must be non-NULL when len > 0. |
| len | Length of buf in bytes. May be 0. |
| consumed | Out: bytes actually accepted (0 .. len). Must be non-NULL. |