Skip to content

Latest commit

 

History

History
167 lines (126 loc) · 5.99 KB

File metadata and controls

167 lines (126 loc) · 5.99 KB

API reference

The complete API lives in include/agfy_rfb.h. This page summarises the surface; the header itself is the source of truth and the doc-comments there cover the per-function contracts.

Lifecycle

agfy_rfb_server_t *agfy_rfb_create(int width, int height,
                                    agfy_rfb_pixfmt_t pixfmt);
void              agfy_rfb_destroy(agfy_rfb_server_t *s);

int  agfy_rfb_listen(agfy_rfb_server_t *s, int port_v4, int port_v6);
int  agfy_rfb_run_async(agfy_rfb_server_t *s);
void agfy_rfb_stop(agfy_rfb_server_t *s);

create allocates a server with an initial framebuffer geometry but no backing buffer; install one with set_frame_buffer. listen binds to loopback and returns 0 on success or -1 on bind failure. run_async returns immediately; the accept loop and per-connection service all run on internal dispatch queues. stop is idempotent and safe to call from any thread; it cancels every connected client and the listener. destroy does an implicit stop first.

Framebuffer

void agfy_rfb_set_frame_buffer(agfy_rfb_server_t *s, void *buffer,
                               size_t padded_row_bytes);
void agfy_rfb_mark_dirty(agfy_rfb_server_t *s,
                         int x1, int y1, int x2, int y2);
void agfy_rfb_set_size(agfy_rfb_server_t *s, int width, int height);

Caller owns the buffer; the library never copies or frees it. padded_row_bytes lets you point at the middle of a larger surface that has its own row stride. Pass 0 to use the natural width × 4 stride.

mark_dirty is the only method clients have for triggering a FramebufferUpdate. Coordinates are half-open: [x1, x2) × [y1, y2). Coordinates are clamped to the framebuffer bounds; out-of-range or empty rectangles are no-ops.

set_size triggers a DesktopSize pseudo-encoding push to every client that negotiated it. Clients without DesktopSize support stay at the original dimensions until they reconnect (per spec).

Hooks

void agfy_rfb_set_new_client_hook(agfy_rfb_server_t *s,
        agfy_rfb_new_client_fn fn, void *user);

void agfy_rfb_set_pointer_event_hook(agfy_rfb_server_t *s,
        agfy_rfb_pointer_event_fn fn, void *user);

void agfy_rfb_set_keyboard_event_hook(agfy_rfb_server_t *s,
        agfy_rfb_keyboard_event_fn fn, void *user);

void agfy_rfb_set_release_all_keys_hook(agfy_rfb_server_t *s,
        agfy_rfb_release_all_keys_fn fn, void *user);

void agfy_rfb_set_cuttext_hook(agfy_rfb_server_t *s,
        agfy_rfb_cuttext_fn fn, void *user);

void agfy_rfb_set_display_hooks(agfy_rfb_server_t *s,
        agfy_rfb_display_fn before, void *bu,
        agfy_rfb_display_fn after,  void *au);

void agfy_rfb_set_client_gone_hook(agfy_rfb_server_t *s,
        agfy_rfb_client_gone_fn fn, void *user);

Every hook fires on the server's internal serial dispatch queue. Hook implementations must not block on caller-side mutexes that any agfy_rfb_* call from the same thread might also be holding.

new_client returns a decision: REJECT, ACCEPT, or ACCEPT_VIEW_ONLY. Returning view-only suppresses pointer and keyboard event delivery for that client.

client_gone fires before the underlying client state is freed. The cl pointer is still valid for the duration of the hook.

display.before / display.after fire around each FramebufferUpdate write — useful for frame-rate metrics or coalescing logging.

Auth

void agfy_rfb_set_password(agfy_rfb_server_t *s, const char *pwd);

void agfy_rfb_set_password_check(agfy_rfb_server_t *s,
        agfy_rfb_password_check_fn fn, void *user);

set_password(NULL) or empty string puts the server in No-Auth mode (security type 1). Any non-empty password switches to VncAuth (security type 2).

The custom check, when registered, runs after the default DES verification succeeds — both must pass. This lets you layer policy (host filters, rate limits, lookups) without re-implementing the crypto.

Clipboard

void agfy_rfb_send_cut_text(agfy_rfb_server_t *s,
                             const char *text, size_t len);

Broadcasts a server cut-text (latin1) to every connected client (RFC 6143 §7.6.4). No-op when no clients are connected. Caller-owned buffer; the library copies internally.

Client query

const char *agfy_rfb_client_host(agfy_rfb_client_t *cl);
int         agfy_rfb_client_socket(agfy_rfb_client_t *cl);

Pointers returned by client_host are valid only for the lifetime of the hook invocation; copy if you need to retain the value.

client_socket returns the underlying TCP fd when one is available, or -1 if the connection runs over a higher-level transport. Embedders that need a stable per-client identity should derive their own value inside new_client and stash it via the user pointer.

Cursor (reserved)

void agfy_rfb_set_cursor(agfy_rfb_server_t *s,
                          agfy_rfb_cursor_kind_t kind,
                          const void *pixels,
                          int width, int height,
                          int hot_x, int hot_y);

The current release records the state but does not push cursor pseudo-encodings to clients. The signature is stable and the data is preserved for a future encoder; do not rely on visible behaviour yet.

Threading model summary

  • Public API methods are safe to call from any thread once run_async has returned.
  • Hooks fire on a single serial dispatch queue. Two hooks never run concurrently on the same Server.
  • mark_dirty enqueues a fan-out onto the server queue and returns immediately; per-client send happens asynchronously.
  • stop blocks long enough to cancel each connection but does not wait for in-flight bytes to drain; pair with a short sleep if you need a quiescent state.

Error handling

The C API uses simple sentinel returns: NULL from constructors, -1 from listen / run_async. There is no error code enum. Failure causes are limited (bad arguments, bind failure, no listener configured); reading the source for the specific call is cheaper than an error API.