Skip to content
Snippets Groups Projects
mongoose.h 196 KiB
Newer Older
#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* MG_ENABLE_MQTT_BROKER */
#endif /* CS_MONGOOSE_SRC_MQTT_BROKER_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/mg_dns.h"
/*
 * Copyright (c) 2014 Cesanta Software Limited
 * All rights reserved
 */

/*
 * === DNS API reference
#ifndef CS_MONGOOSE_SRC_DNS_H_
#define CS_MONGOOSE_SRC_DNS_H_
/* Amalgamated: #include "mg_net.h" */

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#define MG_DNS_A_RECORD 0x01     /* Lookup IP address */
#define MG_DNS_CNAME_RECORD 0x05 /* Lookup CNAME */
#define MG_DNS_PTR_RECORD 0x0c   /* Lookup PTR */
#define MG_DNS_TXT_RECORD 0x10   /* Lookup TXT */
#define MG_DNS_AAAA_RECORD 0x1c  /* Lookup IPv6 address */
#define MG_DNS_SRV_RECORD 0x21   /* Lookup SRV */
#define MG_DNS_MX_RECORD 0x0f    /* Lookup mail server for domain */
#define MG_DNS_ANY_RECORD 0xff
#define MG_DNS_NSEC_RECORD 0x2f
#define MG_MAX_DNS_QUESTIONS 32
#define MG_MAX_DNS_ANSWERS 32
#define MG_DNS_MESSAGE 100 /* High-level DNS message event */
Deomid Ryabkov's avatar
Deomid Ryabkov committed
enum mg_dns_resource_record_kind {
  MG_DNS_INVALID_RECORD = 0,
  MG_DNS_QUESTION,
  MG_DNS_ANSWER
Deomid Ryabkov's avatar
Deomid Ryabkov committed
struct mg_dns_resource_record {
  struct mg_str name; /* buffer with compressed name */
  int rtype;
  int rclass;
  int ttl;
Deomid Ryabkov's avatar
Deomid Ryabkov committed
  enum mg_dns_resource_record_kind kind;
  struct mg_str rdata; /* protocol data (can be a compressed name) */
};

/* DNS message (request and response). */
Deomid Ryabkov's avatar
Deomid Ryabkov committed
struct mg_dns_message {
  struct mg_str pkt; /* packet body */
  uint16_t flags;
  uint16_t transaction_id;
  int num_questions;
  int num_answers;
Deomid Ryabkov's avatar
Deomid Ryabkov committed
  struct mg_dns_resource_record questions[MG_MAX_DNS_QUESTIONS];
  struct mg_dns_resource_record answers[MG_MAX_DNS_ANSWERS];
Deomid Ryabkov's avatar
Deomid Ryabkov committed
struct mg_dns_resource_record *mg_dns_next_record(
    struct mg_dns_message *msg, int query, struct mg_dns_resource_record *prev);
 * Parses the record data from a DNS resource record.
 *
 *  - A:     struct in_addr *ina
 *  - AAAA:  struct in6_addr *ina
 *  - CNAME: char buffer
 *
 * Returns -1 on error.
 *
 * TODO(mkm): MX
 */
int mg_dns_parse_record_data(struct mg_dns_message *msg,
                             struct mg_dns_resource_record *rr, void *data,
                             size_t data_len);
 * Sends a DNS query to the remote end.
void mg_send_dns_query(struct mg_connection *nc, const char *name,
                       int query_type);
 * Inserts a DNS header to an IO buffer.
 * Returns the number of bytes inserted.
int mg_dns_insert_header(struct mbuf *io, size_t pos,
                         struct mg_dns_message *msg);
 * Appends already encoded questions from an existing message.
 *
 * This is useful when generating a DNS reply message which includes
 * all question records.
 *
 * Returns the number of appended bytes.
int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg);
 * Encodes and appends a DNS resource record to an IO buffer.
 *
 * The record metadata is taken from the `rr` parameter, while the name and data
 * are taken from the parameters, encoded in the appropriate format depending on
 * record type and stored in the IO buffer. The encoded values might contain
 * offsets within the IO buffer. It's thus important that the IO buffer doesn't
 * get trimmed while a sequence of records are encoded while preparing a DNS
 * reply.
 *
 * This function doesn't update the `name` and `rdata` pointers in the `rr`
 * struct because they might be invalidated as soon as the IO buffer grows
 * again.
Alexander Alashkin's avatar
Alexander Alashkin committed
 * Returns the number of bytes appended or -1 in case of error.
int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr,
                         const char *name, size_t nlen, const void *rdata,
                         size_t rlen);
/*
 * Encodes a DNS name.
 */
int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len);

/* Low-level: parses a DNS response. */
int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg);
 * Uncompresses a DNS compressed name.
 * The containing DNS message is required because of the compressed encoding
 * and reference suffixes present elsewhere in the packet.
 *
 * If the name is less than `dst_len` characters long, the remainder
 * of `dst` is terminated with `\0` characters. Otherwise, `dst` is not
 * terminated.
 *
 * If `dst_len` is 0 `dst` can be NULL.
 * Returns the uncompressed name length.
size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name,
                              char *dst, int dst_len);
 * Attaches a built-in DNS event handler to the given listening connection.
 * The DNS event handler parses the incoming UDP packets, treating them as DNS
 * requests. If an incoming packet gets successfully parsed by the DNS event
 * handler, a user event handler will receive an `MG_DNS_REQUEST` event, with
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 * `ev_data` pointing to the parsed `struct mg_dns_message`.
 * [captive_dns_server](https://github.com/cesanta/mongoose/tree/master/examples/captive_dns_server)
 * example on how to handle DNS request and send DNS reply.
 */
void mg_set_protocol_dns(struct mg_connection *nc);

#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CS_MONGOOSE_SRC_DNS_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/mg_dns_server.h"
/*
 * Copyright (c) 2014 Cesanta Software Limited
 * All rights reserved
 */

/*
 * === DNS server API reference
 * Disabled by default; enable with `-DMG_ENABLE_DNS_SERVER`.
#ifndef CS_MONGOOSE_SRC_DNS_SERVER_H_
#define CS_MONGOOSE_SRC_DNS_SERVER_H_
#if MG_ENABLE_DNS_SERVER
/* Amalgamated: #include "mg_dns.h" */

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#define MG_DNS_SERVER_DEFAULT_TTL 3600
Deomid Ryabkov's avatar
Deomid Ryabkov committed
struct mg_dns_reply {
  struct mg_dns_message *msg;
 * Creates a DNS reply.
 *
 * The reply will be based on an existing query message `msg`.
 * The query body will be appended to the output buffer.
 * "reply + recursion allowed" will be added to the message flags and the
 * message's num_answers will be set to 0.
 *
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 * Answer records can be appended with `mg_dns_send_reply` or by lower
 * level function defined in the DNS API.
 *
 * In order to send a reply use `mg_dns_send_reply`.
 * It's possible to use a connection's send buffer as reply buffer,
 * and it will work for both UDP and TCP connections.
 *
 * Example:
 *
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 * reply = mg_dns_create_reply(&nc->send_mbuf, msg);
 * for (i = 0; i < msg->num_questions; i++) {
 *   rr = &msg->questions[i];
 *   if (rr->rtype == MG_DNS_A_RECORD) {
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 *     mg_dns_reply_record(&reply, rr, 3600, &dummy_ip_addr, 4);
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 * mg_dns_send_reply(nc, &reply);
struct mg_dns_reply mg_dns_create_reply(struct mbuf *io,
                                        struct mg_dns_message *msg);
 * Appends a DNS reply record to the IO buffer and to the DNS message.
 * The message's num_answers field will be incremented. It's the caller's duty
 * to ensure num_answers is properly initialised.
int mg_dns_reply_record(struct mg_dns_reply *reply,
                        struct mg_dns_resource_record *question,
                        const char *name, int rtype, int ttl, const void *rdata,
                        size_t rdata_len);
 * Sends a DNS reply through a connection.
 *
 * The DNS data is stored in an IO buffer pointed by reply structure in `r`.
 * This function mutates the content of that buffer in order to ensure that
 * the DNS header reflects the size and flags of the message, that might have
 * been updated either with `mg_dns_reply_record` or by direct manipulation of
 * `r->message`.
 *
 * Once sent, the IO buffer will be trimmed unless the reply IO buffer
 * is the connection's send buffer and the connection is not in UDP mode.
 */
void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r);
#endif /* MG_ENABLE_DNS_SERVER */
#endif /* CS_MONGOOSE_SRC_DNS_SERVER_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/mg_resolv.h"
/*
 * Copyright (c) 2014 Cesanta Software Limited
 * All rights reserved
 */

/*
 * === API reference
#ifndef CS_MONGOOSE_SRC_RESOLV_H_
#define CS_MONGOOSE_SRC_RESOLV_H_
/* Amalgamated: #include "mg_dns.h" */

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

enum mg_resolve_err {
  MG_RESOLVE_OK = 0,
  MG_RESOLVE_NO_ANSWERS = 1,
  MG_RESOLVE_EXCEEDED_RETRY_COUNT = 2,
  MG_RESOLVE_TIMEOUT = 3
};

typedef void (*mg_resolve_callback_t)(struct mg_dns_message *dns_message,
                                      void *user_data, enum mg_resolve_err);

/* Options for `mg_resolve_async_opt`. */
struct mg_resolve_async_opts {
  const char *nameserver;
  int max_retries;    /* defaults to 2 if zero */
  int timeout;        /* in seconds; defaults to 5 if zero */
  int accept_literal; /* pseudo-resolve literal ipv4 and ipv6 addrs */
  int only_literal;   /* only resolves literal addrs; sync cb invocation */
  struct mg_connection **dns_conn; /* return DNS connection */
int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query,
                     mg_resolve_callback_t cb, void *data);
/* Set default DNS server */
void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver);

/*
 * Resolved a DNS name asynchronously.
 *
 * Upon successful resolution, the user callback will be invoked
 * with the full DNS response message and a pointer to the user's
 * context `data`.
 *
 * In case of timeout while performing the resolution the callback
 * will receive a NULL `msg`.
 *
 * The DNS answers can be extracted with `mg_next_record` and
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 * `mg_dns_parse_record_data`:
 *
 * [source,c]
 * ----
 * struct in_addr ina;
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 * struct mg_dns_resource_record *rr = mg_next_record(msg, MG_DNS_A_RECORD,
Deomid Ryabkov's avatar
Deomid Ryabkov committed
 * mg_dns_parse_record_data(msg, rr, &ina, sizeof(ina));
int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query,
                         mg_resolve_callback_t cb, void *data,
                         struct mg_resolve_async_opts opts);

/*
 * Resolve a name from `/etc/hosts`.
 *
 * Returns 0 on success, -1 on failure.
 */
int mg_resolve_from_hosts_file(const char *host, union socket_address *usa);

#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CS_MONGOOSE_SRC_RESOLV_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/mg_coap.h"
/*
 * Copyright (c) 2015 Cesanta Software Limited
 * All rights reserved
 * This software is dual-licensed: 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. For the terms of this
 * license, see <http://www.gnu.org/licenses/>.
 *
 * You are free to use this software under the terms of the GNU General
 * Public License, 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.
 *
 * Alternatively, you can license this software under a commercial
 * license, as set out in <https://www.cesanta.com/license>.
 */

/*
 * === CoAP API reference
 * ```
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
 * |Ver| T | TKL | Code | Message ID | Token (if any, TKL bytes) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
 * | Options (if any) ...            |1 1 1 1 1 1 1 1| Payload (if any) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
 * ```
#ifndef CS_MONGOOSE_SRC_COAP_H_
#define CS_MONGOOSE_SRC_COAP_H_
#define MG_COAP_MSG_TYPE_FIELD 0x2
#define MG_COAP_CODE_CLASS_FIELD 0x4
#define MG_COAP_CODE_DETAIL_FIELD 0x8
#define MG_COAP_MSG_ID_FIELD 0x10
#define MG_COAP_TOKEN_FIELD 0x20
#define MG_COAP_OPTIOMG_FIELD 0x40
#define MG_COAP_PAYLOAD_FIELD 0x80
#define MG_COAP_ERROR 0x10000
#define MG_COAP_FORMAT_ERROR (MG_COAP_ERROR | 0x20000)
#define MG_COAP_IGNORE (MG_COAP_ERROR | 0x40000)
#define MG_COAP_NOT_ENOUGH_DATA (MG_COAP_ERROR | 0x80000)
#define MG_COAP_NETWORK_ERROR (MG_COAP_ERROR | 0x100000)
#define MG_COAP_MSG_CON 0
#define MG_COAP_MSG_NOC 1
#define MG_COAP_MSG_ACK 2
#define MG_COAP_MSG_RST 3
#define MG_COAP_MSG_MAX 3
#define MG_COAP_CODECLASS_REQUEST 0
#define MG_COAP_CODECLASS_RESP_OK 2
#define MG_COAP_CODECLASS_CLIENT_ERR 4
#define MG_COAP_CODECLASS_SRV_ERR 5
#define MG_COAP_EVENT_BASE 300
#define MG_EV_COAP_CON (MG_COAP_EVENT_BASE + MG_COAP_MSG_CON)
#define MG_EV_COAP_NOC (MG_COAP_EVENT_BASE + MG_COAP_MSG_NOC)
#define MG_EV_COAP_ACK (MG_COAP_EVENT_BASE + MG_COAP_MSG_ACK)
#define MG_EV_COAP_RST (MG_COAP_EVENT_BASE + MG_COAP_MSG_RST)

/*
 * CoAP options.
 * Use mg_coap_add_option and mg_coap_free_options
 * for creation and destruction.
 */
struct mg_coap_option {
  struct mg_coap_option *next;
  uint32_t number;
  struct mg_str value;
};

/* CoAP message. See RFC 7252 for details. */
struct mg_coap_message {
  uint32_t flags;
  uint8_t msg_type;
  uint8_t code_class;
  uint8_t code_detail;
  uint16_t msg_id;
  struct mg_str token;
  struct mg_coap_option *options;
  struct mg_str payload;
  struct mg_coap_option *optiomg_tail;
};

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* Sets CoAP protocol handler - triggers CoAP specific events. */
int mg_set_protocol_coap(struct mg_connection *nc);

/*
 * Adds a new option to mg_coap_message structure.
 * Returns pointer to the newly created option.
 * Note: options must be freed by using mg_coap_free_options
 */
struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm,
                                          uint32_t number, char *value,
                                          size_t len);

/*
 * Frees the memory allocated for options.
Alexander Alashkin's avatar
Alexander Alashkin committed
 * If the cm parameter doesn't contain any option it does nothing.
 */
void mg_coap_free_options(struct mg_coap_message *cm);

/*
 * Composes a CoAP message from `mg_coap_message`
 * and sends it into `nc` connection.
 * Returns 0 on success. On error, it is a bitmask:
 * - `#define MG_COAP_ERROR 0x10000`
 * - `#define MG_COAP_FORMAT_ERROR (MG_COAP_ERROR | 0x20000)`
 * - `#define MG_COAP_IGNORE (MG_COAP_ERROR | 0x40000)`
 * - `#define MG_COAP_NOT_ENOUGH_DATA (MG_COAP_ERROR | 0x80000)`
 * - `#define MG_COAP_NETWORK_ERROR (MG_COAP_ERROR | 0x100000)`
 */
uint32_t mg_coap_send_message(struct mg_connection *nc,
                              struct mg_coap_message *cm);

/*
 * Composes CoAP acknowledgement from `mg_coap_message`
 * and sends it into `nc` connection.
 * Return value: see `mg_coap_send_message()`
 */
uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id);

/*
 * Parses CoAP message and fills mg_coap_message and returns cm->flags.
 * NOTE: usually CoAP works over UDP, so lack of data means format error.
 * But, in theory, it is possible to use CoAP over TCP (according to RFC)
 * The caller has to check results and treat COAP_NOT_ENOUGH_DATA according to
 * underlying protocol:
 *
 * - in case of UDP COAP_NOT_ENOUGH_DATA means COAP_FORMAT_ERROR,
TheTypoMaster's avatar
TheTypoMaster committed
 * - in case of TCP client can try to receive more data
 *
 * Return value: see `mg_coap_send_message()`
 */
uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm);

/*
 * Composes CoAP message from mg_coap_message structure.
 * This is a helper function.
 * Return value: see `mg_coap_send_message()`
 */
uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* MG_ENABLE_COAP */
#endif /* CS_MONGOOSE_SRC_COAP_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/mg_sntp.h"
#endif
/*
 * Copyright (c) 2016 Cesanta Software Limited
 * All rights reserved
 */

#ifndef CS_MONGOOSE_SRC_SNTP_H_
#define CS_MONGOOSE_SRC_SNTP_H_

#if MG_ENABLE_SNTP

#define MG_SNTP_EVENT_BASE 500

/*
 * Received reply from time server. Event handler parameter contains
 * pointer to mg_sntp_message structure
 */
#define MG_SNTP_REPLY (MG_SNTP_EVENT_BASE + 1)

/* Received malformed SNTP packet */
#define MG_SNTP_MALFORMED_REPLY (MG_SNTP_EVENT_BASE + 2)

/* Failed to get time from server (timeout etc) */
#define MG_SNTP_FAILED (MG_SNTP_EVENT_BASE + 3)

struct mg_sntp_message {
  /* if server sends this flags, user should not send requests to it */
  int kiss_of_death;
  /* usual mg_time */
  double time;
};

/* Establishes connection to given sntp server */
struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr,
                                      MG_CB(mg_event_handler_t event_handler,
                                            void *user_data),
                                      const char *sntp_server_name);

/* Sends time request to given connection */
void mg_sntp_send_request(struct mg_connection *c);

/*
 * Helper function
 * Establishes connection to time server, tries to send request
 * repeats sending SNTP_ATTEMPTS times every SNTP_TIMEOUT sec
 * (if needed)
 * See sntp_client example
 */
struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr,
                                       mg_event_handler_t event_handler,
                                       const char *sntp_server_name);

#endif

#endif /* CS_MONGOOSE_SRC_SNTP_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/mg_socks.h"
#endif
/*
 * Copyright (c) 2017 Cesanta Software Limited
 * All rights reserved
 */

#ifndef CS_MONGOOSE_SRC_SOCKS_H_
#define CS_MONGOOSE_SRC_SOCKS_H_

#if MG_ENABLE_SOCKS

#define MG_SOCKS_VERSION 5

#define MG_SOCKS_HANDSHAKE_DONE MG_F_USER_1
#define MG_SOCKS_CONNECT_DONE MG_F_USER_2

/* SOCKS5 handshake methods */
enum mg_socks_handshake_method {
  MG_SOCKS_HANDSHAKE_NOAUTH = 0,     /* Handshake method - no authentication */
  MG_SOCKS_HANDSHAKE_GSSAPI = 1,     /* Handshake method - GSSAPI auth */
  MG_SOCKS_HANDSHAKE_USERPASS = 2,   /* Handshake method - user/password auth */
  MG_SOCKS_HANDSHAKE_FAILURE = 0xff, /* Handshake method - failure */
};

/* SOCKS5 commands */
enum mg_socks_command {
Deomid Ryabkov's avatar
Deomid Ryabkov committed
  MG_SOCKS_CMD_CONNECT = 1,       /* Command: CONNECT */
  MG_SOCKS_CMD_BIND = 2,          /* Command: BIND */
  MG_SOCKS_CMD_UDP_ASSOCIATE = 3, /* Command: UDP ASSOCIATE */
};

/* SOCKS5 address types */
enum mg_socks_address_type {
Deomid Ryabkov's avatar
Deomid Ryabkov committed
  MG_SOCKS_ADDR_IPV4 = 1,   /* Address type: IPv4 */
  MG_SOCKS_ADDR_DOMAIN = 3, /* Address type: Domain name */
  MG_SOCKS_ADDR_IPV6 = 4,   /* Address type: IPv6 */
};

/* SOCKS5 response codes */
enum mg_socks_response {
  MG_SOCKS_SUCCESS = 0,            /* Response: success */
  MG_SOCKS_FAILURE = 1,            /* Response: failure */
  MG_SOCKS_NOT_ALLOWED = 2,        /* Response: connection not allowed */
  MG_SOCKS_NET_UNREACHABLE = 3,    /* Response: network unreachable */
  MG_SOCKS_HOST_UNREACHABLE = 4,   /* Response: network unreachable */
  MG_SOCKS_CONN_REFUSED = 5,       /* Response: network unreachable */
  MG_SOCKS_TTL_EXPIRED = 6,        /* Response: network unreachable */
  MG_SOCKS_CMD_NOT_SUPPORTED = 7,  /* Response: network unreachable */
  MG_SOCKS_ADDR_NOT_SUPPORTED = 8, /* Response: network unreachable */
};

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* Turn the connection into the SOCKS server */
void mg_set_protocol_socks(struct mg_connection *c);

/* Create socks tunnel for the client connection */
struct mg_iface *mg_socks_mk_iface(struct mg_mgr *, const char *proxy_addr);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif
#endif