2 * This file is part of the libjaylink project.
4 * Copyright (C) 2016-2017 Marc Schink <jaylink-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/types.h>
25 #include <sys/socket.h>
30 #include "libjaylink.h"
31 #include "libjaylink-internal.h"
36 * Socket abstraction layer.
40 * Initiate a connection on a socket.
42 * @param[in] sock Socket descriptor.
43 * @param[in] address Address to establish the connection.
44 * @param[in] length Length of the structure pointed to by @p address in bytes.
45 * @param[in] timeout Connection timeout in milliseconds, 0 for no timeout.
47 * @retval JAYLINK_OK Success.
48 * @retval JAYLINK_ERR_ARG Invalid arguments.
49 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
50 * @retval JAYLINK_ERR Other error conditions.
52 JAYLINK_PRIV
int socket_connect(int sock
, const struct sockaddr
*address
,
53 size_t address_length
, size_t timeout
)
62 return JAYLINK_ERR_ARG
;
64 if (!socket_set_blocking(sock
, false))
67 ret
= connect(sock
, address
, address_length
);
69 if (ret
!= 0 && WSAGetLastError() != WSAEWOULDBLOCK
)
73 ret
= connect(sock
, address
, address_length
);
75 if (ret
!= 0 && errno
!= EINPROGRESS
)
84 tv
.tv_sec
= timeout
/ 1000;
85 tv
.tv_usec
= (timeout
% 1000) * 1000;
87 ret
= select(sock
+ 1, NULL
, &fds
, NULL
, &tv
);
89 socket_set_blocking(sock
, true);
92 return JAYLINK_ERR_TIMEOUT
;
94 option_length
= sizeof(socket_error
);
96 if (!socket_get_option(sock
, SOL_SOCKET
, SO_ERROR
, &socket_error
,
109 * @param[in] sock Socket descriptor.
111 * @return Whether the socket was successfully closed.
113 JAYLINK_PRIV
bool socket_close(int sock
)
118 ret
= closesocket(sock
);
130 * Bind an address to a socket.
132 * @param[in] sock Socket descriptor.
133 * @param[in] address Address to be bound to the socket.
134 * @param[in] length Length of the structure pointed to by @p address in bytes.
136 * @return Whether the address was successfully assigned to the socket.
138 JAYLINK_PRIV
bool socket_bind(int sock
, const struct sockaddr
*address
,
143 ret
= bind(sock
, address
, length
);
146 if (ret
== SOCKET_ERROR
)
157 * Send a message on a socket.
159 * @param[in] sock Socket descriptor.
160 * @param[in] buffer Buffer of the message to be sent.
161 * @param[in,out] length Length of the message in bytes. On success, the value
162 * gets updated with the actual number of bytes sent. The
163 * value is undefined on failure.
164 * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
165 * specify multiple flags.
167 * @return Whether the message was sent successfully.
169 JAYLINK_PRIV
bool socket_send(int sock
, const void *buffer
, size_t *length
,
174 ret
= send(sock
, buffer
, *length
, flags
);
176 if (ret
== SOCKET_ERROR
)
188 * Receive a message from a socket.
190 * @param[in] sock Socket descriptor.
191 * @param[out] buffer Buffer to store the received message on success. Its
192 * content is undefined on failure.
193 * @param[in,out] length Maximum length of the message in bytes. On success,
194 * the value gets updated with the actual number of
195 * received bytes. The value is undefined on failure.
196 * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
197 * specify multiple flags.
199 * @return Whether a message was successfully received.
201 JAYLINK_PRIV
bool socket_recv(int sock
, void *buffer
, size_t *length
,
206 ret
= recv(sock
, buffer
, *length
, flags
);
209 if (ret
== SOCKET_ERROR
)
222 * Send a message on a socket.
224 * @param[in] sock Socket descriptor.
225 * @param[in] buffer Buffer to send message from.
226 * @param[in,out] length Number of bytes to send. On success, the value gets
227 * updated with the actual number of bytes sent. The
228 * value is undefined on failure.
229 * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
230 * specify multiple flags.
231 * @param[in] address Destination address of the message.
232 * @param[in] address_length Length of the structure pointed to by @p address
235 * @return Whether the message was successfully sent.
237 JAYLINK_PRIV
bool socket_sendto(int sock
, const void *buffer
, size_t *length
,
238 int flags
, const struct sockaddr
*address
,
239 size_t address_length
)
243 ret
= sendto(sock
, buffer
, *length
, flags
, address
, address_length
);
246 if (ret
== SOCKET_ERROR
)
259 * Receive a message from a socket.
261 * @param[in] sock Socket descriptor.
262 * @param[out] buffer Buffer to store the received message on success. Its
263 * content is undefined on failure.
264 * @param[in,out] length Maximum length of the message in bytes. On success,
265 * the value gets updated with the actual number of
266 * received bytes. The value is undefined on failure.
267 * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
268 * specify multiple flags.
269 * @param[out] address Structure to store the source address of the message on
270 * success. Its content is undefined on failure.
272 * @param[in,out] address_length Length of the structure pointed to by
273 * @p address in bytes. On success, the value
274 * gets updated with the actual length of the
275 * structure. The value is undefined on failure.
276 * Should be NULL if @p address is NULL.
278 * @return Whether a message was successfully received.
280 JAYLINK_PRIV
bool socket_recvfrom(int sock
, void *buffer
, size_t *length
,
281 int flags
, struct sockaddr
*address
, size_t *address_length
)
287 tmp
= *address_length
;
288 ret
= recvfrom(sock
, buffer
, *length
, flags
, address
, &tmp
);
290 if (ret
== SOCKET_ERROR
)
295 tmp
= *address_length
;
296 ret
= recvfrom(sock
, buffer
, *length
, flags
, address
, &tmp
);
302 *address_length
= tmp
;
309 * Get the value of a socket option.
311 * @param[in] sock Socket descriptor.
312 * @param[in] level Level at which the option is defined.
313 * @param[in] option Option to get the value for.
314 * @param[in] value Buffer to store the value.
315 * @param[in] length Length of the value buffer in bytes.
317 * @return Whether the option value was retrieved successfully.
319 JAYLINK_PRIV
bool socket_get_option(int sock
, int level
, int option
,
320 void *value
, size_t *length
)
322 if (!getsockopt(sock
, level
, option
, value
, (socklen_t
*)length
))
329 * Set the value of a socket option.
331 * @param[in] sock Socket descriptor.
332 * @param[in] level Level at which the option is defined.
333 * @param[in] option Option to set the value for.
334 * @param[in] value Buffer of the value to be set.
335 * @param[in] length Length of the value buffer in bytes.
337 * @return Whether the option value was set successfully.
339 JAYLINK_PRIV
bool socket_set_option(int sock
, int level
, int option
,
340 const void *value
, size_t length
)
342 if (!setsockopt(sock
, level
, option
, value
, length
))
349 * Set the blocking mode of a socket.
351 * @param[in] sock Socket descriptor.
352 * @param[in] blocking Blocking mode.
354 * @return Whether the blocking mode was set successfully.
356 JAYLINK_PRIV
bool socket_set_blocking(int sock
, bool blocking
)
363 ret
= ioctlsocket(sock
, FIONBIO
, &mode
);
370 flags
= fcntl(sock
, F_GETFL
, 0);
376 flags
&= ~O_NONBLOCK
;
380 ret
= fcntl(sock
, F_SETFL
, flags
);