libssh2_session_callback_set2(3)

πŸ’– libssh2_session_callback_set2 β€” the callback-gluing page, from the libssh2 manual ✨

okay bestie, buckle up, because this one is literally about plugging your own functions into libssh2 and letting it call them for you. it's giving "build your own I/O layer" energy πŸ¦‹


🌸 NAME 🌸

libssh2_session_callback_set2 β€” set a callback function πŸ’…


✨ SYNOPSIS ✨

#include <libssh2.h>

libssh2_cb_generic *
libssh2_session_callback_set2(LIBSSH2_SESSION *session, int cbtype,
                              libssh2_cb_generic *callback);

πŸŽ€ DESCRIPTION πŸŽ€

So basically, this sets a custom callback handler on a session object that you already initialized (yes, libssh2_session_init_ex(3) first, no skipping steps bestie 🫢). These callbacks get triggered when special packets show up at the Transport layer. And if you want to disable one? Just set it to NULL. bye boo πŸ‘‹

  • session β€” the Session instance, as returned by libssh2_session_init_ex(3) πŸ’œ
  • cbtype β€” the callback type. One of the types listed down in Callback Types. πŸ‘‘
  • callback β€” pointer to your custom callback function. the prototype for it must match the associated callback declaration macro, no improvising fr fr 😭

🌈 CALLBACK TYPES 🌈

  • LIBSSH2_CALLBACK_IGNORE β€” gets called when a SSH_MSG_IGNORE message is received ✨
  • LIBSSH2_CALLBACK_DEBUG β€” gets called when a SSH_MSG_DEBUG message is received πŸ›
  • LIBSSH2_CALLBACK_DISCONNECT β€” gets called when a SSH_MSG_DISCONNECT message is received πŸ’€
  • LIBSSH2_CALLBACK_MACERROR β€” gets called when a mismatched MAC has been detected in the transport layer. and listen, if the function returns 0, the packet gets accepted anyway. like, "eh, close enough" 😭
  • LIBSSH2_CALLBACK_X11 β€” gets called when an X11 connection has been accepted πŸ–₯️
  • LIBSSH2_CALLBACK_SEND β€” gets called when libssh2 wants to send data on the connection. you can set this to a custom function to handle I/O your own way, main character behavior πŸ’…

the prototype of the callback:

ssize_t sendcb(libssh2_socket_t sockfd, const void *buffer,
               size_t length, int flags, void **abstract);

so: sockfd is the socket to write to, buffer points to the data to send, length is the size of the data, flags is the flags that would have been used to a send() call, and abstract is a pointer to the abstract pointer you set in the libssh2_session_init_ex(3) call. iykyk 🫢

the callback returns the number of bytes sent, or -1 for error. and there's a special return code, -EAGAIN, that you can return to signal that the send was aborted to prevent getting blocked and it needs to be called again. iconic escape hatch ngl πŸ”₯

  • LIBSSH2_CALLBACK_RECV β€” gets called when libssh2 wants to read data from the connection. same deal, set it to a custom function to handle I/O your own way πŸ’«

the prototype of the callback:

ssize_t recvcb(libssh2_socket_t sockfd, void *buffer,
               size_t length, int flags, void **abstract);

so: sockfd is the socket to read from, buffer is where to store received data into, length is the size of the buffer, flags is the flags that would have been used to a recv() call, and abstract is a pointer to the abstract pointer set in the libssh2_session_init_ex(3) call 🌸

the callback returns the number of bytes read, or -1 for error. and again, the special return code -EAGAIN can be returned to signal that the read was aborted to prevent getting blocked and it needs to be called again ⭐

  • LIBSSH2_CALLBACK_AUTHAGENT β€” gets called during the authentication process, so the client can connect to the ssh-agent and do any setup, like configuring the agent or adding keys πŸ”‘

the prototype of the callback:

void authagent(LIBSSH2_SESSION* session, LIBSSH2_CHANNEL *channel,
               void **abstract);
  • LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES β€” not called by libssh2. the client is responsible for calling this method when a SSH2_AGENTC_REQUEST_IDENTITIES message has been received πŸ‘€

the prototype of the callback:

void identities(LIBSSH2_SESSION* session, void *buffer,
                const char *agent_path,
                void **abstract)

buffer must be filled in by the callback. different clients may implement this differently β€” for example, one client may pass in an unsigned char ** for this parameter, while another may pass in a pointer to a struct. so it's flexible, bestie 🧚

regardless of the type of buffer used, the client will need to send back a list of identities in the following format:

uint32 buffer length
uint32 number of entries
entries

where each entry in the entries list is of the format:

string data
cstring comment

agent_path β€” the path to a running ssh-agent on the client machine, from which identities can be listed 🐚

  • LIBSSH2_CALLBACK_AUTHAGENT_SIGN β€” not called by libssh2. the client is responsible for calling this method when a SSH2_AGENTC_SIGN_REQUEST message has been received ✍️

the prototype of the callback:

void sign(LIBSSH2_SESSION* session,
          unsigned char *blob, unsigned int blen,
          const unsigned char *data, unsigned int dlen,
          unsigned char **sig, unsigned int *sig_len,
          const char *agent_path,
          void **abstract);

when you're interfacing with an ssh-agent installed on the client system, this method can call libssh2_agent_sign(3) to perform the signing. slay πŸŽ€


πŸ’œ RETURN VALUE πŸ’œ

a pointer to the previous callback handler. and it returns NULL if no prior callback handler was set, or if the callback type was unknown. so yeah, unknown type = NULL, no drama πŸ™ˆ


πŸ‘‘ SEE ALSO πŸ‘‘


and that's the whole page, bestie!! this one's from libssh2 1.11.1, dated 13 Dec 2023 β€” go forth and set some callbacks, you absolute legend πŸ«ΆπŸ’–βœ¨πŸŒˆ