summaryrefslogtreecommitdiff
path: root/src/rexmpp_socks.h
blob: 340f7247ae3d354ceefc773f74a98b056c0c6a17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
   @file rexmpp_socks.h
   @brief SOCKS5 connection establishment.
   @author defanor <defanor@uberspace.net>
   @date 2020
   @copyright MIT license.
*/

#ifndef REXMPP_SOCKS_H
#define REXMPP_SOCKS_H

#include <unistd.h>


#define REXMPP_SOCKS_BUF_LEN 300

/**
   @brief Whether we are reading or writing.
*/
enum socks_io_state {
  /** Attempting to send data to the server. */
  REXMPP_SOCKS_WRITING,
  /** Attempting to receive data from the server. */
  REXMPP_SOCKS_READING
};

/**
   @brief SOCKS5 connection stage.
*/
enum socks_stage {
  /** Authentication stage. */
  REXMPP_SOCKS_AUTH,
  /** Command sending stage. */
  REXMPP_SOCKS_CMD,
  /** Done. */
  REXMPP_SOCKS_DONE
};

/**
   @brief Status/error codes.
*/
enum socks_err {
  /** Connected successfully. */
  REXMPP_SOCKS_CONNECTED,
  /** Connection in progress. */
  REXMPP_SOCKS_E_AGAIN,
  /** A TCP error. */
  REXMPP_SOCKS_E_TCP,
  /** Malformed or unrecognised reply from a server. */
  REXMPP_SOCKS_E_REPLY,
  /** Wrong server SOCKS version. */
  REXMPP_SOCKS_E_VERSION,
  /** An error is reported by the server, the code is stored in
      ::rexmpp_socks's @c socks_error */
  REXMPP_SOCKS_E_SOCKS,
  /** Host name is too long (can be 255 bytes at most). */
  REXMPP_SOCKS_E_HOST
};

/**
   @brief SOCKS5 connection state.
*/
struct rexmpp_socks {
  /** @brief A file descriptor. */
  int fd;
  /** @brief A host we are connecting to. */
  const char *host;
  /** @brief A port we are connecting to. */
  uint16_t port;
  /** @brief Current connection stage. */
  enum socks_stage stage;
  /** @brief I/O state: whether we are reading or writing. */
  enum socks_io_state io_state;
  /** @brief A SOCKS5 error code, as returned by the server. */
  int socks_error;
  /** @brief A buffer used to receive and send packets. */
  char buf[REXMPP_SOCKS_BUF_LEN];
  /** @brief How many bytes of useful data are in the buffer. */
  size_t buf_len;
  /** @brief How many bytes were sent so far. */
  size_t buf_sent;
};
typedef struct rexmpp_socks rexmpp_socks_t;

/**
   @brief Continues a SOCKS5 connection establishment.
   @param[in,out] s An initialised ::rexmpp_socks structure.
   @returns A ::socks_err code.

   While ::REXMPP_SOCKS_E_AGAIN is returned, this function should be
   called repeatedly when the socket state is suitable for
   ::rexmpp_socks's ::socks_io_state.
*/
enum socks_err
rexmpp_socks_proceed (rexmpp_socks_t *s);

/**
   @brief Initialises a SOCKS5 connection over a connected socket.
   @param[out] s An allocated ::rexmpp_socks structure.
   @param[in] fd A socket file descriptor. This is supposed to be
   connected to a SOCKS5 server.
   @param[in] host A host to connect to.
   @param[in] port A port to connect to.
   @returns ::REXMPP_SOCKS_E_HOST or the return value of the first
   ::rexmpp_socks_proceed invocation.
*/
enum socks_err
rexmpp_socks_init (rexmpp_socks_t *s,
                   int fd,
                   const char *host,
                   uint16_t port);


#endif