modemu2k 0.2.3
Library that provides telnet capability to a comm program
Loading...
Searching...
No Matches
modemu2k.h File Reference

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_tm2k_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

Detailed Description

Public API for the modemu2k PTY-based modem emulator library.

Typical usage

The pattern used by the bundled modemu2k executable (see src/main.c) shows the recommended way to use the library:

m2k_t *ctx = m2k_new();
if (!ctx) return EXIT_FAILURE;
// Choose one setup mode:
m2k_setup_stdin(ctx); // read/write stdin/stdout
// m2k_setup_comm_program(ctx, "minicom -p %s"); // fork a comm program on a PTY
// m2k_setup_listen(ctx, "5000"); // bind a TCP port, then
// m2k_listen_accept(ctx); // wait for a client to connect
// Optional: apply AT commands before entering the command loop
m2k_atcmd(ctx, "ATS7=30");
// Run the full command/online state machine (blocks until session ends)
m2k_run(ctx);
m2k_free(ctx);
M2K_API m2k_err_t m2k_run(m2k_t *ctx)
Run the modem command/online loop until the PTY closes.
M2K_API void m2k_free(m2k_t *ctx)
Release all resources held by ctx.
M2K_API m2k_err_t m2k_setup_stdin(m2k_t *ctx)
Use stdin/stdout as the TTY (standalone mode).
struct m2k_s m2k_t
Opaque modem emulator context. Create with m2k_new(), destroy with m2k_free().
Definition modemu2k.h:95
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_t * m2k_new(void)
Allocate and initialise a new modem context.

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.

Macro Definition Documentation

◆ M2K_API

#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).

◆ M2K_ERROR_BUFFER_SIZE

#define M2K_ERROR_BUFFER_SIZE   256

Recommended minimum size for the m2k_set_error_buffer() buffer.

◆ M2K_MAX_POLLFDS

#define M2K_MAX_POLLFDS   3

Maximum number of pollfds modemu2k will ever ask the caller to watch.

Typedef Documentation

◆ m2k_log_fn

typedef void(* m2k_log_fn) (const char *msg, void *userdata)

Log callback type.

Parameters
msgNUL-terminated log message.
userdataCaller-supplied pointer passed unchanged from m2k_set_log_fn().

Enumeration Type Documentation

◆ m2k_err_t

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).

Function Documentation

◆ m2k_atcmd()

M2K_API m2k_err_t m2k_atcmd ( m2k_t * ctx,
const char * cmd )

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.

Parameters
ctxModem context.
cmdNUL-terminated AT command (e.g. "ATZ" or "ATS0=1"). A string with no AT prefix is silently ignored.
Returns
M2K_OK on successful execution or no-op (missing 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.
m2k_atcmd(ctx, "ATZ"); // reset to defaults
m2k_atcmd(ctx, "ATS0=1"); // auto-answer on first ring
Examples
main.c.

◆ M2K_DEPRECATED()

M2K_API M2K_DEPRECATED ( "use m2k_run() or the step API instead" )

Open a TCP connection to host : port.

Enter online mode and relay data between the PTY and the socket.

Deprecated
Slated for removal in 0.3.0. Drive the state machine via m2k_run() or the step API (m2k_get_pollfds + m2k_step) and let the AT lexer dispatch the dial.

Transitions the modem from idle to connected state. Call m2k_online() after this to start relaying data.

Parameters
ctxModem context.
hostHostname or numeric IP address.
portService name or decimal port number.
Returns
M2K_OK on success, M2K_ERR_SOCKET on failure.
/* ATS7 sets the dial timeout (seconds); AT%D1 disables non-TTY dial
cancel so a stray stdin byte can't abort the dial. */
static int run_dial(m2k_t *ctx, const char *host, const char *port)
{
m2k_atcmd(ctx, "ATS7=20");
m2k_atcmd(ctx, "AT%D1");
m2k_err_t err = m2k_dial(ctx, host, port);
if (err != M2K_OK) {
fprintf(stderr, "dial: %s\n", m2k_strerror(err));
return 1;
}
sleep(1);
m2k_hangup(ctx);
return 0;
}
Deprecated
Slated for removal in 0.3.0. Use m2k_run() or the step API (m2k_get_pollfds + m2k_step) instead — they share one state-machine implementation with the rest of the library.

Blocks until the connection closes or the +++ escape sequence is detected. Returns M2K_ERR_CANCELED when the caller escapes back to command mode.

Parameters
ctxModem context (must have an active connection from m2k_dial()).
Returns
M2K_OK when the remote end closes, M2K_ERR_CANCELED on +++ escape.

◆ m2k_escape()

M2K_API m2k_err_t m2k_escape ( m2k_t * ctx)

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.

Parameters
ctxModem context.
Returns
M2K_OK.

◆ m2k_free()

M2K_API void m2k_free ( m2k_t * ctx)

Release all resources held by ctx.

Parameters
ctxContext to destroy. Safe to call with NULL.
Examples
main.c.

◆ m2k_get_dtr()

M2K_API int m2k_get_dtr ( const m2k_t * ctx)

Return the most recent value passed to m2k_set_dtr() (1 by default).

◆ m2k_get_force_verbose()

M2K_API int m2k_get_force_verbose ( const m2k_t * ctx)

Return the most recent value passed to m2k_set_force_verbose() (0 by default).

◆ m2k_get_listen_fd()

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).

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.

Parameters
ctxModem context.
Returns
The fd of a bound-but-not-yet-accepted listener, or -1 when no listener is open (either never set up, or already accepted).

◆ m2k_get_pollfds()

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().

Parameters
ctxModem context.
fdsCaller-provided array of at least M2K_MAX_POLLFDS entries.
nfds_inoutIn: 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_msOut: maximum wait in milliseconds before m2k_step() needs to be called again. -1 means no deadline.
Returns
M2K_OK on success, M2K_ERR_BUG if *nfds_inout is too small.

◆ m2k_get_rts()

M2K_API int m2k_get_rts ( const m2k_t * ctx)

Return the most recent value passed to m2k_set_rts() (1 by default).

◆ m2k_hangup()

M2K_API m2k_err_t m2k_hangup ( m2k_t * ctx)

Tear down the active TCP connection.

Parameters
ctxModem context.
Returns
M2K_OK on success.

◆ m2k_has_carrier()

M2K_API int m2k_has_carrier ( const m2k_t * ctx)

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.

Parameters
ctxModem context.
Returns
Nonzero when a connection is alive, zero otherwise.

◆ m2k_has_pending_output()

M2K_API int m2k_has_pending_output ( const m2k_t * ctx)

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.

Parameters
ctxModem context.
Returns
Nonzero if buffered output is pending, zero otherwise.

◆ m2k_is_online()

M2K_API int m2k_is_online ( const m2k_t * ctx)

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.

Parameters
ctxModem context.
Returns
Nonzero in online mode, zero in command mode or after the session has ended.

◆ 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.

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().

Parameters
ctxModem context (must have an active listener from m2k_setup_listen()).
Returns
M2K_OK on success, M2K_ERR_SOCKET on accept failure (including interruption by a signal) or if no listener has been set up. On failure the listener is closed regardless; a fresh m2k_setup_listen() is required to retry.
Examples
main.c.

◆ m2k_new()

M2K_API m2k_t * m2k_new ( void )

Allocate and initialise a new modem context.

Returns
Newly allocated context, or NULL on memory exhaustion.
Examples
main.c.

◆ m2k_read_to_app()

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.

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).

Back-pressure shape
After m2k_step() processes an incoming socket burst, the internal TTY-bound buffer may hold more bytes than a single read_to_app call can return. The host must not block in poll() while bytes remain pending — none of modemu2k's fds will fire to wake it. Use one of:
  • Loop on read_to_app until m2k_has_pending_output() returns 0; or
  • On a partial drain (got < max OR you only wanted a small chunk), check m2k_has_pending_output() and use a zero timeout on the next poll() so the next read_to_app runs immediately.

Skipping this collapses throughput to roughly "your buffer size per poll timeout."

Parameters
ctxModem context.
bufDestination buffer. Must be non-NULL when max > 0.
maxMaximum bytes to copy. May be 0.
len_outOut: number of bytes actually copied (0 means no data). Must be non-NULL.
Returns
M2K_OK on success, M2K_ERR_PTY (overloaded as "wrong I/O mode") if the context is not in app-I/O mode — call m2k_setup_app_io() first.

◆ m2k_run()

M2K_API m2k_err_t m2k_run ( m2k_t * ctx)

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:

while (!m2k_run_done(ctx)) {
struct pollfd fds[M2K_MAX_POLLFDS];
size_t nfds = M2K_MAX_POLLFDS;
int timeout_ms;
m2k_get_pollfds(ctx, fds, &nfds, &timeout_ms);
poll(fds, nfds, timeout_ms);
m2k_step(ctx, fds, nfds);
}
M2K_API int m2k_run_done(const m2k_t *ctx)
Test whether the session has ended.
#define M2K_MAX_POLLFDS
Definition modemu2k.h:535
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 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.
Parameters
ctxModem context.
Returns
M2K_OK when the session ends normally.
Examples
main.c.

◆ m2k_run_done()

M2K_API int m2k_run_done ( const m2k_t * ctx)

Test whether the session has ended.

Parameters
ctxModem context.
Returns
Nonzero when the state machine has reached a terminal state (PTY closed, etc.) and the caller's loop should stop.

◆ m2k_set_dtr()

M2K_API void m2k_set_dtr ( m2k_t * ctx,
int on )

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).

Parameters
ctxModem context.
onNon-zero to assert DTR, zero to drop it.

◆ m2k_set_error_buffer()

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.

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.

Parameters
ctxModem context.
bufCaller-owned buffer that outlives the context, or NULL to detach. Recommended size: M2K_ERROR_BUFFER_SIZE.
sizeCapacity 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.
char errbuf[M2K_ERROR_BUFFER_SIZE];
m2k_set_error_buffer(ctx, errbuf, sizeof(errbuf));
if (m2k_atcmd(ctx, "AT~not~a~real~command") != M2K_OK)
fprintf(stderr, "modemu2k: %s\n", errbuf);

◆ m2k_set_force_verbose()

M2K_API void m2k_set_force_verbose ( m2k_t * ctx,
int on )

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.

Parameters
ctxModem context.
onNon-zero to force narration on, zero to defer to ATV.
Examples
main.c.

◆ m2k_set_log_fn()

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.

Parameters
ctxModem context.
fnCallback to receive log messages, or NULL.
userdataOpaque pointer forwarded to every fn invocation.
/* Userdata is passed through unchanged to the callback. */
static void my_logger(const char *msg, void *userdata)
{
FILE *log = userdata;
fputs(msg, log);
}
m2k_set_log_fn(ctx, my_logger, stderr);
Examples
main.c.

◆ m2k_set_rts()

M2K_API void m2k_set_rts ( m2k_t * ctx,
int on )

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).

Parameters
ctxModem context.
onNon-zero to assert RTS, zero to drop it.

◆ m2k_setup_app_io()

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().

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.

Parameters
ctxModem context.
Returns
M2K_OK.

◆ m2k_setup_comm_program()

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.

The slave device path is substituted for s in cmd. Call before m2k_run().

Parameters
ctxModem context.
cmdShell command; s is replaced by the slave device path.
Returns
M2K_OK on success, M2K_ERR_PTY or M2K_ERR_NOMEM on failure.
/* Fork minicom on the PTY slave; %s is substituted with the slave path. */
m2k_err_t err = m2k_setup_comm_program(ctx, "minicom -l -tansi -con -p %s");
if (err != M2K_OK) {
fprintf(stderr, "setup_comm_program failed: %s\n", m2k_strerror(err));
m2k_free(ctx);
return 1;
}
m2k_run(ctx); /* blocks until the comm program exits */
Examples
main.c.

◆ m2k_setup_dev()

M2K_API m2k_err_t m2k_setup_dev ( m2k_t * ctx,
const char * dev )

Open an existing PTY device as the TTY.

Parameters
ctxModem context.
devPath to the PTY master device (e.g. "/dev/ptyp0").
Returns
M2K_OK on success, M2K_ERR_PTY if the device cannot be opened.
Examples
main.c.

◆ m2k_setup_listen()

M2K_API m2k_err_t m2k_setup_listen ( m2k_t * ctx,
const char * port )

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.

Parameters
ctxModem context.
portService name or decimal port number to listen on.
Returns
M2K_OK on success, M2K_ERR_SOCKET on failure. All bind / listen / getaddrinfo failures (port in use, address family unavailable, etc.) funnel through M2K_ERR_SOCKET; pair with m2k_set_error_buffer() to recover the specific cause.
/* Bind TCP port 5000, accept one connection, then drive the modem state
machine over the accepted socket. Pair with -l/--listen on the CLI for
the same flow. */
static int run_listener(m2k_t *ctx, const char *port)
{
m2k_err_t err = m2k_setup_listen(ctx, port);
if (err != M2K_OK) {
fprintf(stderr, "setup_listen: %s\n", m2k_strerror(err));
return 1;
}
err = m2k_listen_accept(ctx); /* blocks until a client connects */
if (err != M2K_OK) {
fprintf(stderr, "listen_accept: %s\n", m2k_strerror(err));
return 1;
}
m2k_run(ctx);
return 0;
}
Examples
main.c.

◆ m2k_setup_pty()

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.

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().

Parameters
ctxModem context.
slave_outOut: pointer to a NUL-terminated slave path inside ctx. Must be non-NULL.
Returns
M2K_OK on success, M2K_ERR_PTY on failure.
Examples
main.c.

◆ m2k_setup_stdin()

M2K_API m2k_err_t m2k_setup_stdin ( m2k_t * ctx)

Use stdin/stdout as the TTY (standalone mode).

Puts the terminal into raw mode. Call before m2k_run().

Parameters
ctxModem context.
Returns
M2K_OK.
Examples
main.c.

◆ m2k_step()

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.

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).

Parameters
ctxModem context.
fdsThe pollfd array previously filled by m2k_get_pollfds(), with the OS's .revents values populated by the caller.
nfdsNumber of entries in fds (the value m2k_get_pollfds returned in *nfds_inout).
Returns
M2K_OK on success.

◆ m2k_strerror()

M2K_API const char * m2k_strerror ( m2k_err_t err)

Return a human-readable string for err.

Parameters
errError code.
Returns
Static string; never NULL. Codes outside the m2k_err_t range return a generic "Unknown error".

◆ m2k_version()

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).

Returns
Static "MAJOR.MINOR.PATCH" string; never NULL, never owned by the caller.

◆ m2k_write_from_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.

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.

Parameters
ctxModem context.
bufBytes to inject. Must be non-NULL when len > 0.
lenLength of buf in bytes. May be 0.
consumedOut: bytes actually accepted (0 .. len). Must be non-NULL.
Returns
M2K_OK if any bytes were accepted, M2K_ERR_WOULDBLOCK if none were, M2K_ERR_PTY (overloaded as "wrong I/O mode") if the context is not in app-I/O mode — call m2k_setup_app_io() first.