File: obex_msg.c

package info (click to toggle)
libopenobex 1.7.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, stretch
  • size: 972 kB
  • ctags: 1,552
  • sloc: ansic: 9,988; xml: 407; makefile: 96
file content (241 lines) | stat: -rw-r--r-- 5,707 bytes parent folder | download | duplicates (2)
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/**
 * @file obex_msg.c
 *
 * Bridge between obex object and raw message buffer.
 * OpenOBEX library - Free implementation of the Object Exchange protocol.
 *
 * Copyright (c) 2012 Hendrik Sattler, All Rights Reserved.
 *
 * OpenOBEX is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with OpenOBEX. If not, see <http://www.gnu.org/>.
 */

#include "obex_msg.h"

#include "obex_main.h"
#include "obex_object.h"
#include "obex_hdr.h"
#include "defines.h"

static unsigned int obex_srm_tx_flags_decode (uint8_t flag)
{
	switch (flag) {
	case 0x00:
		return OBEX_SRM_FLAG_WAIT_LOCAL;

	case 0x01:
		return OBEX_SRM_FLAG_WAIT_REMOTE;

	case 0x02:
		return (OBEX_SRM_FLAG_WAIT_LOCAL | OBEX_SRM_FLAG_WAIT_REMOTE);

	default:
		return 0;
	}
}

static unsigned int obex_srm_rx_flags_decode (uint8_t flag)
{
	switch (flag) {
	case 0x00:
		return OBEX_SRM_FLAG_WAIT_REMOTE;

	case 0x01:
		return OBEX_SRM_FLAG_WAIT_LOCAL;

	case 0x02:
		return (OBEX_SRM_FLAG_WAIT_LOCAL | OBEX_SRM_FLAG_WAIT_REMOTE);

	default:
		return 0;
	}
}

static bool obex_msg_post_prepare(obex_t *self, obex_object_t *object,
				  const struct obex_hdr_it *from,
				  const struct obex_hdr_it *to)
{
	struct obex_hdr_it it;
	struct obex_hdr *hdr;

	obex_hdr_it_init_from(&it, from);
	hdr = obex_hdr_it_get(&it);

	/* loop over all headers in that are non-NULL and finished... */
	while (hdr != NULL && obex_hdr_is_finished(hdr)) {
		if (self->rsp_mode == OBEX_RSP_MODE_SINGLE &&
		    obex_hdr_get_id(hdr) == OBEX_HDR_ID_SRM_FLAGS)
		{
			const uint8_t *data = obex_hdr_get_data_ptr(hdr);

			self->srm_flags &= ~OBEX_SRM_FLAG_WAIT_REMOTE;
			self->srm_flags |= obex_srm_tx_flags_decode(data[0]);
		}

		/* ...but only in the range [from..to]. The last entry
		 * must be included if it is finished. */
		if (obex_hdr_it_equals(&it, to))
			break;

		obex_hdr_it_next(&it);
		hdr = obex_hdr_it_get(&it);
	}

	return true;
}

bool obex_msg_prepare(obex_t *self, obex_object_t *object, bool allowfinal)
{
	buf_t *txmsg = self->tx_msg;
	uint16_t tx_left = self->mtu_tx - sizeof(struct obex_common_hdr);
	int real_opcode;
	struct obex_hdr_it it;

	obex_hdr_it_init_from(&it, object->tx_it);

	if (!obex_data_request_init(self))
		return false;

	if (!obex_object_append_data(object, txmsg, tx_left))
		return false;

	real_opcode = obex_object_get_opcode(self->object, allowfinal,
					     self->mode);
	DEBUG(4, "Generating packet with opcode %d\n", real_opcode);
	obex_data_request_prepare(self, real_opcode);

	return obex_msg_post_prepare(self, object, &it, object->tx_it);
}

int obex_msg_getspace(obex_t *self, obex_object_t *object, unsigned int flags)
{
	size_t objlen = sizeof(struct obex_common_hdr);

	if (flags & OBEX_FL_FIT_ONE_PACKET)
		objlen += obex_object_get_size(object);

	return self->mtu_tx - objlen;
}

/** Check if the RX message buffer contains at least one full message. */
bool obex_msg_rx_status(const obex_t *self)
{
	buf_t *msg = self->rx_msg;
	obex_common_hdr_t *hdr = buf_get(msg);

	return (buf_get_length(msg) >= sizeof(*hdr) &&
		buf_get_length(msg) >= ntohs(hdr->len));
}

/** Check if the TX message buffer was sent completely */
bool obex_msg_tx_status(const obex_t *self)
{
	buf_t *msg = self->tx_msg;

	return (buf_get_length(msg) == 0);
}

int obex_msg_get_opcode(const obex_t *self)
{
	buf_t *msg = self->rx_msg;
	obex_common_hdr_t *hdr = buf_get(msg);

	if (!obex_msg_rx_status(self))
		return -1;

	return hdr->opcode;
}

size_t obex_msg_get_len(const obex_t *self)
{
	buf_t *msg = self->rx_msg;
	obex_common_hdr_t *hdr;

	if (!obex_msg_rx_status(self))
		return -1;

	hdr = buf_get(msg);
	return (size_t)ntohs(hdr->len);
}

void obex_msg_pre_receive(obex_t *self)
{
	if (self->rsp_mode == OBEX_RSP_MODE_SINGLE)
		self->srm_flags &= ~OBEX_SRM_FLAG_WAIT_LOCAL;
}

int obex_msg_post_receive(obex_t *self)
{
	obex_object_t *object = self->object;
	struct obex_hdr *hdr;

	if (!object->rx_it)
		return 0;

	/* loop over all new headers */
	hdr = obex_hdr_it_get(object->rx_it);
	while (hdr != NULL) {
		if (self->rsp_mode == OBEX_RSP_MODE_SINGLE &&
		    obex_hdr_get_id(hdr) == OBEX_HDR_ID_SRM_FLAGS)
		{
			const uint8_t *data = obex_hdr_get_data_ptr(hdr);

			self->srm_flags |= obex_srm_rx_flags_decode(data[0]);
		}

		obex_hdr_it_next(object->rx_it);
		hdr = obex_hdr_it_get(object->rx_it);
	}

	return 0;
}

int obex_msg_receive_filtered(obex_t *self, obex_object_t *object,
			      uint64_t filter, bool first_run)
{
	buf_t *msg = self->rx_msg;
	size_t len;
	const uint8_t *data;
	int hlen;

	DEBUG(4, "\n");

	if (!obex_msg_rx_status(self))
		return 0;

	data = buf_get(msg);
	len = sizeof(struct obex_common_hdr);
	if (first_run)
		obex_msg_pre_receive(self);

	data += len;
	len = obex_msg_get_len(self) - len;
	if (first_run && len > 0)
		if (obex_object_receive_nonhdr_data(object, data, len) < 0)
			return -1;

	data += object->headeroffset;
	len -= object->headeroffset;
	if (len > 0) {
		hlen = obex_object_receive_headers(object, data, len, filter);
		if (hlen < 0)
			return hlen;
	}	

	return obex_msg_post_receive(self);
}

int obex_msg_receive(obex_t *self, obex_object_t *object)
{
	return obex_msg_receive_filtered(self, object, 0, TRUE);
}