aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/osmo_io_internal.h
blob: a4b0749df230c42008fc8da4e25153057d174cfd (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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*! \file osmo_io_internal.h */

#pragma once

#include <unistd.h>
#include <stdbool.h>
#include <netinet/sctp.h>

#include <osmocom/core/osmo_io.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>

#include "../config.h"

#define OSMO_IO_DEFAULT_MSGB_SIZE 1024
#define OSMO_IO_DEFAULT_MSGB_HEADROOM 128

extern const struct iofd_backend_ops iofd_poll_ops;
#define OSMO_IO_BACKEND_DEFAULT "POLL"

#if defined(HAVE_URING)
extern const struct iofd_backend_ops iofd_uring_ops;
#endif

struct iofd_backend_ops {
	int (*register_fd)(struct osmo_io_fd *iofd);
	int (*unregister_fd)(struct osmo_io_fd *iofd);
	int (*close)(struct osmo_io_fd *iofd);
	void (*write_enable)(struct osmo_io_fd *iofd);
	void (*write_disable)(struct osmo_io_fd *iofd);
	void (*read_enable)(struct osmo_io_fd *iofd);
	void (*read_disable)(struct osmo_io_fd *iofd);
	void (*notify_connected)(struct osmo_io_fd *iofd);
};

#define IOFD_FLAG_CLOSED (1<<0)
#define IOFD_FLAG_IN_CALLBACK (1<<1)
#define IOFD_FLAG_TO_FREE (1<<2)
#define IOFD_FLAG_NOTIFY_CONNECTED (1<<3)
#define IOFD_FLAG_FD_REGISTERED (1<<4)

#define IOFD_FLAG_SET(iofd, flag) \
	(iofd)->flags |= (flag)

#define IOFD_FLAG_UNSET(iofd, flag) \
	(iofd)->flags &= ~(flag)

#define IOFD_FLAG_ISSET(iofd, flag) ((iofd)->flags & (flag))

struct osmo_io_fd {
	/*! linked list for internal management */
	struct llist_head list;
	/*! actual operating-system level file decriptor */
	int fd;
	/*! type of read/write mode to use */
	enum osmo_io_fd_mode mode;

	/*! flags to guard closing/freeing of iofd */
	uint32_t flags;

	/*! human-readable name to associte with fd */
	char *name;

	/*! send/recv (msg) callback functions */
	struct osmo_io_ops io_ops;
	/*! Pending msgb to keep partial data during segmentation */
	struct msgb *pending;

	/*! data pointer passed through to call-back function */
	void *data;
	/*! private number, extending \a data */
	unsigned int priv_nr;

	/*! size of iofd_msghdr.cmsg[] when allocated in recvmsg path */
	size_t cmsg_size;

	struct {
		/*! talloc context from which to allocate msgb when reading */
		const void *ctx;
		/*! size of msgb to allocate (excluding headroom) */
		unsigned int size;
		/*! headroom to allocate when allocating msgb's */
		unsigned int headroom;
	} msgb_alloc;

	struct {
		/*! maximum length of write queue */
		unsigned int max_length;
		/*! current length of write queue */
		unsigned int current_length;
		/*! actual linked list implementing the transmit queue */
		struct llist_head msg_queue;
	} tx_queue;

	union {
		struct {
			struct osmo_fd ofd;
		} poll;
		struct {
			bool read_enabled;
			bool write_enabled;
			void *read_msghdr;
			void *write_msghdr;
			/* TODO: index into array of registered fd's? */
			/* osmo_fd for non-blocking connect handling */
			struct osmo_fd connect_ofd;
		} uring;
	} u;
};

enum iofd_msg_action {
	IOFD_ACT_READ,
	IOFD_ACT_WRITE,
	IOFD_ACT_RECVFROM,
	IOFD_ACT_SENDTO,
	IOFD_ACT_RECVMSG,
	IOFD_ACT_SENDMSG,
};


/*! serialized version of 'struct msghdr' employed by sendmsg/recvmsg */
struct iofd_msghdr {
	/*! entry into osmo_io_fd.tx_queue.msg_queue */
	struct llist_head list;
	enum iofd_msg_action action;
	/*! the 'struct msghdr' we are wrapping/ecapsulating here */
	struct msghdr hdr;
	/*! socket address of the remote peer */
	struct osmo_sockaddr osa;
	/*! io-vector we need to pass as argument to sendmsg/recvmsg; is set up
	 * to point into msg below */
	struct iovec iov[1];
	/*! flags we pass as argument to sendmsg / recvmsg */
	int flags;

	/*! message-buffer containing data for this I/O operation */
	struct msgb *msg;
	/*! I/O file descriptor on which we perform this I/O operation */
	struct osmo_io_fd *iofd;

	/*! control message buffer for passing sctp_sndrcvinfo along */
	char cmsg[0]; /* size is determined by iofd->cmsg_size on recvmsg, and by mcghdr->msg_controllen on sendmsg */
};

enum iofd_seg_act {
	IOFD_SEG_ACT_HANDLE_ONE,
	IOFD_SEG_ACT_HANDLE_MORE,
	IOFD_SEG_ACT_DEFER,
};

struct iofd_msghdr *iofd_msghdr_alloc(struct osmo_io_fd *iofd, enum iofd_msg_action action, struct msgb *msg, size_t cmsg_size);
void iofd_msghdr_free(struct iofd_msghdr *msghdr);

struct msgb *iofd_msgb_alloc(struct osmo_io_fd *iofd);
struct msgb *iofd_msgb_pending(struct osmo_io_fd *iofd);
struct msgb *iofd_msgb_pending_or_alloc(struct osmo_io_fd *iofd);

void iofd_handle_recv(struct osmo_io_fd *iofd, struct msgb *msg, int rc, struct iofd_msghdr *msghdr);
void iofd_handle_send_completion(struct osmo_io_fd *iofd, int rc, struct iofd_msghdr *msghdr);
void iofd_handle_segmented_read(struct osmo_io_fd *iofd, struct msgb *msg, int rc);

int iofd_txqueue_enqueue(struct osmo_io_fd *iofd, struct iofd_msghdr *msghdr);
void iofd_txqueue_enqueue_front(struct osmo_io_fd *iofd, struct iofd_msghdr *msghdr);
struct iofd_msghdr *iofd_txqueue_dequeue(struct osmo_io_fd *iofd);