summaryrefslogtreecommitdiffstats
path: root/src/io.c
blob: 15f60e4a6f3c607cb127542be52eca6b7cb3d7da (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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 * libdect IO functions
 *
 * Copyright (c) 2009-2010 Patrick McHardy <kaber@trash.net>
 *
 * This program is free software; 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.
 */

/**
 * @addtogroup events
 * @{
 *
 * @defgroup io I/O
 *
 * libdect file and socket I/O.
 *
 * libdect uses various file descriptors for I/O internally. The application
 * using libdect must register the callback functions
 * dect_event_ops::register_fd() and dect_event_ops::unregister_fd() in
 * struct dect_event_ops to allow libdect to register it's file descriptors
 * with the application's event handler. The function dect_fd_num() can be used
 * to get the file decriptor number. When an event occurs, the function
 * dect_fd_handle() must be invoked with a bitmask of enum #dect_fd_events
 * specifying the events that occured. All events except the file descriptor
 * becoming writable map to #DECT_FD_READ.
 *
 * Each libdect file descriptor contains a storage area of the size specified
 * in dect_event_ops::fd_priv_size, which can be used by the application to
 * associate data with the file descriptor. The function dect_fd_priv() returns
 * a pointer to this data area.
 *
 * @{
 */

#include <unistd.h>
#include <stdint.h>
#include <inttypes.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <libdect.h>
#include <utils.h>
#include <io.h>

#ifndef SOCK_NONBLOCK
#define SOCK_NONBLOCK O_NONBLOCK
#endif

struct dect_fd *dect_fd_alloc(const struct dect_handle *dh)
{
	struct dect_fd *dfd;

	dfd = dect_malloc(dh, sizeof(struct dect_fd) +
			  dh->ops->event_ops->fd_priv_size);
	if (dfd == NULL)
		return NULL;
	dfd->fd    = -1;
	dfd->state = DECT_FD_UNREGISTERED;
	return dfd;
}
EXPORT_SYMBOL(dect_fd_alloc);

/**
 * Get a pointer to the private data area from a libdect file descriptor
 *
 * @param dfd		libdect file descriptor
 */
void *dect_fd_priv(struct dect_fd *dfd)
{
	return dfd->priv;
}
EXPORT_SYMBOL(dect_fd_priv);

/**
 * Get the file descriptor number from a libdect file descriptor.
 *
 * @param dfd		libdect file descriptor
 */
int dect_fd_num(const struct dect_fd *dfd)
{
	return dfd->fd;
}
EXPORT_SYMBOL(dect_fd_num);

void dect_fd_setup(struct dect_fd *dfd,
		   void (*cb)(struct dect_handle *, struct dect_fd *, uint32_t),
		   void *data)
{
	dfd->callback = cb;
	dfd->data = data;
}
EXPORT_SYMBOL(dect_fd_setup);

int dect_fd_register(const struct dect_handle *dh, struct dect_fd *dfd,
		     uint32_t events)
{
	int err;

	dect_assert(dfd->state == DECT_FD_UNREGISTERED);
	err = dh->ops->event_ops->register_fd(dh, dfd, events);
	if (err == 0)
		dfd->state = DECT_FD_REGISTERED;
	return err;
}
EXPORT_SYMBOL(dect_fd_register);

void dect_fd_unregister(const struct dect_handle *dh, struct dect_fd *dfd)
{
	dect_assert(dfd->state == DECT_FD_REGISTERED);
	dh->ops->event_ops->unregister_fd(dh, dfd);
	dfd->state = DECT_FD_UNREGISTERED;
}
EXPORT_SYMBOL(dect_fd_unregister);

/**
 * Process libdect file descriptor events
 *
 * @param dh		libdect DECT handle
 * @param dfd		libdect file descriptor
 * @param events	Bitmask of file descriptor events (#dect_fd_events)
 *
 * Process the events specified by the events bitmask for the given file
 * descriptor.
 */
void dect_fd_process(struct dect_handle *dh, struct dect_fd *dfd, uint32_t events)
{
	dect_assert(dfd->state == DECT_FD_REGISTERED);
	dfd->callback(dh, dfd, events);
}
EXPORT_SYMBOL(dect_fd_process);

void dect_close(const struct dect_handle *dh, struct dect_fd *dfd)
{
	dect_assert(dfd->state == DECT_FD_UNREGISTERED);
	if (dfd->fd >= 0)
		close(dfd->fd);
	dect_free(dh, dfd);
}
EXPORT_SYMBOL(dect_close);

struct dect_fd *dect_socket(const struct dect_handle *dh, int type, int protocol)
{
	struct dect_fd *dfd;

	dfd = dect_fd_alloc(dh);
	if (dfd == NULL)
		goto err1;

	dfd->fd = socket(AF_DECT, type | SOCK_NONBLOCK, protocol);
	if (dfd->fd < 0)
		goto err2;

	return dfd;

err2:
	dect_close(dh, dfd);
err1:
	return NULL;
}

struct dect_fd *dect_accept(const struct dect_handle *dh,
			    const struct dect_fd *dfd,
			    struct sockaddr *addr, socklen_t len)
{
	struct dect_fd *nfd;

	nfd = dect_fd_alloc(dh);
	if (nfd == NULL)
		goto err1;

	nfd->fd = accept(dfd->fd, addr, &len);
	if (nfd->fd < 0)
		goto err2;
	if (fcntl(nfd->fd, F_SETFL, O_NONBLOCK) < 0)
		goto err2;

	return nfd;

err2:
	dect_close(dh, nfd);
err1:
	return NULL;
}

/** @} */
/** @} */