Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Merge Requests
0
Merge Requests
0
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Jean-Baptiste Kempf
vlc
Commits
a5152175
Commit
a5152175
authored
Mar 14, 2018
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
network: split TLS and generic/TCP stream support
parent
1bfa2c2c
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
452 additions
and
409 deletions
+452
-409
src/Makefile.am
src/Makefile.am
+1
-0
src/network/stream.c
src/network/stream.c
+449
-0
src/network/tls.c
src/network/tls.c
+2
-409
No files found.
src/Makefile.am
View file @
a5152175
...
...
@@ -304,6 +304,7 @@ libvlccore_la_SOURCES = \
network/tcp.c
\
network/udp.c
\
network/rootbind.c
\
network/stream.c
\
network/tls.c
\
text/charset.c
\
text/memstream.c
\
...
...
src/network/stream.c
0 → 100644
View file @
a5152175
/*****************************************************************************
* stream.c
*****************************************************************************
* Copyright © 2004-2016 Rémi Denis-Courmont
* $Id$
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/**
* @ingroup transport
* @file
* Transport-layer stream abstraction
*
* This file implements the transport-layer stream (vlc_tls) abstraction.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_POLL
# include <poll.h>
#endif
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#ifdef HAVE_NETINET_TCP_H
# include <netinet/tcp.h>
#endif
#ifndef SOL_TCP
# define SOL_TCP IPPROTO_TCP
#endif
#include <vlc_common.h>
#include <vlc_tls.h>
#include <vlc_interrupt.h>
ssize_t
vlc_tls_Read
(
vlc_tls_t
*
session
,
void
*
buf
,
size_t
len
,
bool
waitall
)
{
struct
pollfd
ufd
;
struct
iovec
iov
;
ufd
.
fd
=
vlc_tls_GetFD
(
session
);
ufd
.
events
=
POLLIN
;
iov
.
iov_base
=
buf
;
iov
.
iov_len
=
len
;
for
(
size_t
rcvd
=
0
;;)
{
if
(
vlc_killed
())
{
errno
=
EINTR
;
return
-
1
;
}
ssize_t
val
=
session
->
readv
(
session
,
&
iov
,
1
);
if
(
val
>
0
)
{
if
(
!
waitall
)
return
val
;
iov
.
iov_base
=
(
char
*
)
iov
.
iov_base
+
val
;
iov
.
iov_len
-=
val
;
rcvd
+=
val
;
}
if
(
iov
.
iov_len
==
0
||
val
==
0
)
return
rcvd
;
if
(
val
==
-
1
)
{
if
(
vlc_killed
())
return
-
1
;
if
(
errno
!=
EINTR
&&
errno
!=
EAGAIN
)
return
rcvd
?
(
ssize_t
)
rcvd
:
-
1
;
}
vlc_poll_i11e
(
&
ufd
,
1
,
-
1
);
}
}
ssize_t
vlc_tls_Write
(
vlc_tls_t
*
session
,
const
void
*
buf
,
size_t
len
)
{
struct
pollfd
ufd
;
struct
iovec
iov
;
ufd
.
fd
=
vlc_tls_GetFD
(
session
);
ufd
.
events
=
POLLOUT
;
iov
.
iov_base
=
(
void
*
)
buf
;
iov
.
iov_len
=
len
;
for
(
size_t
sent
=
0
;;)
{
if
(
vlc_killed
())
{
errno
=
EINTR
;
return
-
1
;
}
ssize_t
val
=
session
->
writev
(
session
,
&
iov
,
1
);
if
(
val
>
0
)
{
iov
.
iov_base
=
((
char
*
)
iov
.
iov_base
)
+
val
;
iov
.
iov_len
-=
val
;
sent
+=
val
;
}
if
(
iov
.
iov_len
==
0
||
val
==
0
)
return
sent
;
if
(
val
==
-
1
)
{
if
(
vlc_killed
())
return
-
1
;
if
(
errno
!=
EINTR
&&
errno
!=
EAGAIN
)
return
sent
?
(
ssize_t
)
sent
:
-
1
;
}
vlc_poll_i11e
(
&
ufd
,
1
,
-
1
);
}
}
char
*
vlc_tls_GetLine
(
vlc_tls_t
*
session
)
{
char
*
line
=
NULL
;
size_t
linelen
=
0
,
linesize
=
0
;
do
{
if
(
linelen
==
linesize
)
{
linesize
+=
1024
;
char
*
newline
=
realloc
(
line
,
linesize
);
if
(
unlikely
(
newline
==
NULL
))
goto
error
;
line
=
newline
;
}
if
(
vlc_tls_Read
(
session
,
line
+
linelen
,
1
,
false
)
<=
0
)
goto
error
;
}
while
(
line
[
linelen
++
]
!=
'\n'
);
if
(
linelen
>=
2
&&
line
[
linelen
-
2
]
==
'\r'
)
line
[
linelen
-
2
]
=
'\0'
;
return
line
;
error:
free
(
line
);
return
NULL
;
}
typedef
struct
vlc_tls_socket
{
struct
vlc_tls
tls
;
int
fd
;
socklen_t
peerlen
;
struct
sockaddr
peer
[];
}
vlc_tls_socket_t
;
static
int
vlc_tls_SocketGetFD
(
vlc_tls_t
*
tls
)
{
vlc_tls_socket_t
*
sock
=
(
struct
vlc_tls_socket
*
)
tls
;
return
sock
->
fd
;
}
static
ssize_t
vlc_tls_SocketRead
(
vlc_tls_t
*
tls
,
struct
iovec
*
iov
,
unsigned
count
)
{
struct
msghdr
msg
=
{
.
msg_iov
=
iov
,
.
msg_iovlen
=
count
,
};
return
recvmsg
(
vlc_tls_SocketGetFD
(
tls
),
&
msg
,
0
);
}
static
ssize_t
vlc_tls_SocketWrite
(
vlc_tls_t
*
tls
,
const
struct
iovec
*
iov
,
unsigned
count
)
{
const
struct
msghdr
msg
=
{
.
msg_iov
=
(
struct
iovec
*
)
iov
,
.
msg_iovlen
=
count
,
};
return
sendmsg
(
vlc_tls_SocketGetFD
(
tls
),
&
msg
,
MSG_NOSIGNAL
);
}
static
int
vlc_tls_SocketShutdown
(
vlc_tls_t
*
tls
,
bool
duplex
)
{
return
shutdown
(
vlc_tls_SocketGetFD
(
tls
),
duplex
?
SHUT_RDWR
:
SHUT_WR
);
}
static
void
vlc_tls_SocketClose
(
vlc_tls_t
*
tls
)
{
net_Close
(
vlc_tls_SocketGetFD
(
tls
));
free
(
tls
);
}
static
vlc_tls_t
*
vlc_tls_SocketAlloc
(
int
fd
,
const
struct
sockaddr
*
restrict
peer
,
socklen_t
peerlen
)
{
vlc_tls_socket_t
*
sock
=
malloc
(
sizeof
(
*
sock
)
+
peerlen
);
if
(
unlikely
(
sock
==
NULL
))
return
NULL
;
vlc_tls_t
*
tls
=
&
sock
->
tls
;
tls
->
get_fd
=
vlc_tls_SocketGetFD
;
tls
->
readv
=
vlc_tls_SocketRead
;
tls
->
writev
=
vlc_tls_SocketWrite
;
tls
->
shutdown
=
vlc_tls_SocketShutdown
;
tls
->
close
=
vlc_tls_SocketClose
;
tls
->
p
=
NULL
;
sock
->
fd
=
fd
;
sock
->
peerlen
=
peerlen
;
if
(
peerlen
>
0
)
memcpy
(
sock
->
peer
,
peer
,
peerlen
);
return
tls
;
}
vlc_tls_t
*
vlc_tls_SocketOpen
(
int
fd
)
{
return
vlc_tls_SocketAlloc
(
fd
,
NULL
,
0
);
}
int
vlc_tls_SocketPair
(
int
family
,
int
protocol
,
vlc_tls_t
*
pair
[
2
])
{
int
fds
[
2
];
if
(
vlc_socketpair
(
family
,
SOCK_STREAM
,
protocol
,
fds
,
true
))
return
-
1
;
for
(
size_t
i
=
0
;
i
<
2
;
i
++
)
{
setsockopt
(
fds
[
i
],
SOL_SOCKET
,
SO_REUSEADDR
,
&
(
int
){
1
},
sizeof
(
int
));
pair
[
i
]
=
vlc_tls_SocketAlloc
(
fds
[
i
],
NULL
,
0
);
if
(
unlikely
(
pair
[
i
]
==
NULL
))
{
net_Close
(
fds
[
i
]);
if
(
i
)
vlc_tls_SessionDelete
(
pair
[
0
]);
else
net_Close
(
fds
[
1
]);
return
-
1
;
}
}
return
0
;
}
/**
* Allocates an unconnected transport layer socket.
*/
static
vlc_tls_t
*
vlc_tls_SocketAddrInfo
(
const
struct
addrinfo
*
restrict
info
)
{
int
fd
=
vlc_socket
(
info
->
ai_family
,
info
->
ai_socktype
,
info
->
ai_protocol
,
true
/* nonblocking */
);
if
(
fd
==
-
1
)
return
NULL
;
setsockopt
(
fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
(
int
){
1
},
sizeof
(
int
));
if
(
info
->
ai_socktype
==
SOCK_STREAM
&&
info
->
ai_protocol
==
IPPROTO_TCP
)
setsockopt
(
fd
,
SOL_TCP
,
TCP_NODELAY
,
&
(
int
){
1
},
sizeof
(
int
));
vlc_tls_t
*
sk
=
vlc_tls_SocketAlloc
(
fd
,
info
->
ai_addr
,
info
->
ai_addrlen
);
if
(
unlikely
(
sk
==
NULL
))
net_Close
(
fd
);
return
sk
;
}
/**
* Waits for pending transport layer socket connection.
*/
static
int
vlc_tls_WaitConnect
(
vlc_tls_t
*
tls
)
{
const
int
fd
=
vlc_tls_GetFD
(
tls
);
struct
pollfd
ufd
;
ufd
.
fd
=
fd
;
ufd
.
events
=
POLLOUT
;
do
{
if
(
vlc_killed
())
{
errno
=
EINTR
;
return
-
1
;
}
}
while
(
vlc_poll_i11e
(
&
ufd
,
1
,
-
1
)
<=
0
);
int
val
;
socklen_t
len
=
sizeof
(
val
);
if
(
getsockopt
(
fd
,
SOL_SOCKET
,
SO_ERROR
,
&
val
,
&
len
))
return
-
1
;
if
(
val
!=
0
)
{
errno
=
val
;
return
-
1
;
}
return
0
;
}
/**
* Connects a transport layer socket.
*/
static
ssize_t
vlc_tls_Connect
(
vlc_tls_t
*
tls
)
{
const
vlc_tls_socket_t
*
sock
=
(
vlc_tls_socket_t
*
)
tls
;
if
(
connect
(
sock
->
fd
,
sock
->
peer
,
sock
->
peerlen
)
==
0
)
return
0
;
#ifndef _WIN32
if
(
errno
!=
EINPROGRESS
)
return
-
1
;
#else
if
(
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
return
-
1
;
#endif
return
vlc_tls_WaitConnect
(
tls
);
}
/* Callback for combined connection establishment and initial send */
static
ssize_t
vlc_tls_ConnectWrite
(
vlc_tls_t
*
tls
,
const
struct
iovec
*
iov
,
unsigned
count
)
{
#ifdef MSG_FASTOPEN
vlc_tls_socket_t
*
sock
=
(
vlc_tls_socket_t
*
)
tls
;
const
struct
msghdr
msg
=
{
.
msg_name
=
sock
->
peer
,
.
msg_namelen
=
sock
->
peerlen
,
.
msg_iov
=
(
struct
iovec
*
)
iov
,
.
msg_iovlen
=
count
,
};
ssize_t
ret
;
/* Next time, write directly. Do not retry to connect. */
tls
->
writev
=
vlc_tls_SocketWrite
;
ret
=
sendmsg
(
vlc_tls_SocketGetFD
(
tls
),
&
msg
,
MSG_NOSIGNAL
|
MSG_FASTOPEN
);
if
(
ret
>=
0
)
{
/* Fast open in progress */
return
ret
;
}
if
(
errno
==
EINPROGRESS
)
{
if
(
vlc_tls_WaitConnect
(
tls
))
return
-
1
;
}
else
if
(
errno
!=
EOPNOTSUPP
)
return
-
1
;
/* Fast open not supported or disabled... fallback to normal mode */
#else
tls
->
writev
=
vlc_tls_SocketWrite
;
#endif
if
(
vlc_tls_Connect
(
tls
))
return
-
1
;
return
vlc_tls_SocketWrite
(
tls
,
iov
,
count
);
}
vlc_tls_t
*
vlc_tls_SocketOpenAddrInfo
(
const
struct
addrinfo
*
restrict
info
,
bool
defer_connect
)
{
vlc_tls_t
*
sock
=
vlc_tls_SocketAddrInfo
(
info
);
if
(
sock
==
NULL
)
return
NULL
;
if
(
defer_connect
)
{
/* The socket is not connected yet.
* The connection will be triggered on the first send. */
sock
->
writev
=
vlc_tls_ConnectWrite
;
}
else
{
if
(
vlc_tls_Connect
(
sock
))
{
vlc_tls_SessionDelete
(
sock
);
sock
=
NULL
;
}
}
return
sock
;
}
vlc_tls_t
*
vlc_tls_SocketOpenTCP
(
vlc_object_t
*
obj
,
const
char
*
name
,
unsigned
port
)
{
struct
addrinfo
hints
=
{
.
ai_socktype
=
SOCK_STREAM
,
.
ai_protocol
=
IPPROTO_TCP
,
},
*
res
;
assert
(
name
!=
NULL
);
msg_Dbg
(
obj
,
"resolving %s ..."
,
name
);
int
val
=
vlc_getaddrinfo_i11e
(
name
,
port
,
&
hints
,
&
res
);
if
(
val
!=
0
)
{
/* TODO: C locale for gai_strerror() */
msg_Err
(
obj
,
"cannot resolve %s port %u: %s"
,
name
,
port
,
gai_strerror
(
val
));
return
NULL
;
}
msg_Dbg
(
obj
,
"connecting to %s port %u ..."
,
name
,
port
);
/* TODO: implement RFC8305 */
for
(
const
struct
addrinfo
*
p
=
res
;
p
!=
NULL
;
p
=
p
->
ai_next
)
{
vlc_tls_t
*
tls
=
vlc_tls_SocketOpenAddrInfo
(
p
,
false
);
if
(
tls
==
NULL
)
{
msg_Err
(
obj
,
"connection error: %s"
,
vlc_strerror_c
(
errno
));
continue
;
}
freeaddrinfo
(
res
);
return
tls
;
}
freeaddrinfo
(
res
);
return
NULL
;
}
src/network/tls.c
View file @
a5152175
...
...
@@ -20,10 +20,9 @@
*****************************************************************************/
/**
* @ingroup tls
* @file
* Transport Layer Socket abstraction.
*
* This file implements the Transport Layer Socket (vlc_tls) abstraction.
* Transport Layer Session protocol API.
*/
#ifdef HAVE_CONFIG_H
...
...
@@ -35,15 +34,6 @@
#endif
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#ifdef HAVE_NETINET_TCP_H
# include <netinet/tcp.h>
#endif
#ifndef SOL_TCP
# define SOL_TCP IPPROTO_TCP
#endif
...
...
@@ -225,403 +215,6 @@ vlc_tls_t *vlc_tls_ServerSessionCreate(vlc_tls_creds_t *crd,
return
vlc_tls_SessionCreate
(
crd
,
sock
,
NULL
,
alpn
);
}
ssize_t
vlc_tls_Read
(
vlc_tls_t
*
session
,
void
*
buf
,
size_t
len
,
bool
waitall
)
{
struct
pollfd
ufd
;
struct
iovec
iov
;
ufd
.
fd
=
vlc_tls_GetFD
(
session
);
ufd
.
events
=
POLLIN
;
iov
.
iov_base
=
buf
;
iov
.
iov_len
=
len
;
for
(
size_t
rcvd
=
0
;;)
{
if
(
vlc_killed
())
{
errno
=
EINTR
;
return
-
1
;
}
ssize_t
val
=
session
->
readv
(
session
,
&
iov
,
1
);
if
(
val
>
0
)
{
if
(
!
waitall
)
return
val
;
iov
.
iov_base
=
(
char
*
)
iov
.
iov_base
+
val
;
iov
.
iov_len
-=
val
;
rcvd
+=
val
;
}
if
(
iov
.
iov_len
==
0
||
val
==
0
)
return
rcvd
;
if
(
val
==
-
1
)
{
if
(
vlc_killed
())
return
-
1
;
if
(
errno
!=
EINTR
&&
errno
!=
EAGAIN
)
return
rcvd
?
(
ssize_t
)
rcvd
:
-
1
;
}
vlc_poll_i11e
(
&
ufd
,
1
,
-
1
);
}
}
ssize_t
vlc_tls_Write
(
vlc_tls_t
*
session
,
const
void
*
buf
,
size_t
len
)
{
struct
pollfd
ufd
;
struct
iovec
iov
;
ufd
.
fd
=
vlc_tls_GetFD
(
session
);
ufd
.
events
=
POLLOUT
;
iov
.
iov_base
=
(
void
*
)
buf
;
iov
.
iov_len
=
len
;
for
(
size_t
sent
=
0
;;)
{
if
(
vlc_killed
())
{
errno
=
EINTR
;
return
-
1
;
}
ssize_t
val
=
session
->
writev
(
session
,
&
iov
,
1
);
if
(
val
>
0
)
{
iov
.
iov_base
=
((
char
*
)
iov
.
iov_base
)
+
val
;
iov
.
iov_len
-=
val
;
sent
+=
val
;
}
if
(
iov
.
iov_len
==
0
||
val
==
0
)
return
sent
;
if
(
val
==
-
1
)
{
if
(
vlc_killed
())
return
-
1
;
if
(
errno
!=
EINTR
&&
errno
!=
EAGAIN
)
return
sent
?
(
ssize_t
)
sent
:
-
1
;
}
vlc_poll_i11e
(
&
ufd
,
1
,
-
1
);
}
}
char
*
vlc_tls_GetLine
(
vlc_tls_t
*
session
)
{
char
*
line
=
NULL
;
size_t
linelen
=
0
,
linesize
=
0
;
do
{
if
(
linelen
==
linesize
)
{
linesize
+=
1024
;
char
*
newline
=
realloc
(
line
,
linesize
);
if
(
unlikely
(
newline
==
NULL
))
goto
error
;
line
=
newline
;
}
if
(
vlc_tls_Read
(
session
,
line
+
linelen
,
1
,
false
)
<=
0
)
goto
error
;
}
while
(
line
[
linelen
++
]
!=
'\n'
);
if
(
linelen
>=
2
&&
line
[
linelen
-
2
]
==
'\r'
)
line
[
linelen
-
2
]
=
'\0'
;
return
line
;
error:
free
(
line
);
return
NULL
;
}
typedef
struct
vlc_tls_socket
{
struct
vlc_tls
tls
;
int
fd
;
socklen_t
peerlen
;
struct
sockaddr
peer
[];
}
vlc_tls_socket_t
;
static
int
vlc_tls_SocketGetFD
(
vlc_tls_t
*
tls
)
{
vlc_tls_socket_t
*
sock
=
(
struct
vlc_tls_socket
*
)
tls
;
return
sock
->
fd
;
}
static
ssize_t
vlc_tls_SocketRead
(
vlc_tls_t
*
tls
,
struct
iovec
*
iov
,
unsigned
count
)
{
struct
msghdr
msg
=
{
.
msg_iov
=
iov
,
.
msg_iovlen
=
count
,
};
return
recvmsg
(
vlc_tls_SocketGetFD
(
tls
),
&
msg
,
0
);
}
static
ssize_t
vlc_tls_SocketWrite
(
vlc_tls_t
*
tls
,
const
struct
iovec
*
iov
,
unsigned
count
)
{
const
struct
msghdr
msg
=
{
.
msg_iov
=
(
struct
iovec
*
)
iov
,
.
msg_iovlen
=
count
,
};
return
sendmsg
(
vlc_tls_SocketGetFD
(
tls
),
&
msg
,
MSG_NOSIGNAL
);
}
static
int
vlc_tls_SocketShutdown
(
vlc_tls_t
*
tls
,
bool
duplex
)
{
return
shutdown
(
vlc_tls_SocketGetFD
(
tls
),
duplex
?
SHUT_RDWR
:
SHUT_WR
);
}
static
void
vlc_tls_SocketClose
(
vlc_tls_t
*
tls
)
{
net_Close
(
vlc_tls_SocketGetFD
(
tls
));
free
(
tls
);
}
static
vlc_tls_t
*
vlc_tls_SocketAlloc
(
int
fd
,
const
struct
sockaddr
*
restrict
peer
,
socklen_t
peerlen
)
{
vlc_tls_socket_t
*
sock
=
malloc
(
sizeof
(
*
sock
)
+
peerlen
);
if
(
unlikely
(
sock
==
NULL
))
return
NULL
;
vlc_tls_t
*
tls
=
&
sock
->
tls
;
tls
->
get_fd
=
vlc_tls_SocketGetFD
;
tls
->
readv
=
vlc_tls_SocketRead
;
tls
->
writev
=
vlc_tls_SocketWrite
;
tls
->
shutdown
=
vlc_tls_SocketShutdown
;
tls
->
close
=
vlc_tls_SocketClose
;
tls
->
p
=
NULL
;
sock
->
fd
=
fd
;
sock
->
peerlen
=
peerlen
;
if
(
peerlen
>
0
)
memcpy
(
sock
->
peer
,
peer
,
peerlen
);
return
tls
;
}
vlc_tls_t
*
vlc_tls_SocketOpen
(
int
fd
)
{
return
vlc_tls_SocketAlloc
(
fd
,
NULL
,
0
);
}
int
vlc_tls_SocketPair
(
int
family
,
int
protocol
,
vlc_tls_t
*
pair
[
2
])
{
int
fds
[
2
];
if
(
vlc_socketpair
(
family
,
SOCK_STREAM
,
protocol
,
fds
,
true
))
return
-
1
;
for
(
size_t
i
=
0
;
i
<
2
;
i
++
)
{
setsockopt
(
fds
[
i
],
SOL_SOCKET
,
SO_REUSEADDR
,
&
(
int
){
1
},
sizeof
(
int
));
pair
[
i
]
=
vlc_tls_SocketAlloc
(
fds
[
i
],
NULL
,
0
);
if
(
unlikely
(
pair
[
i
]
==
NULL
))
{
net_Close
(
fds
[
i
]);
if
(
i
)
vlc_tls_SessionDelete
(
pair
[
0
]);
else
net_Close
(
fds
[
1
]);
return
-
1
;
}
}
return
0
;
}
/**
* Allocates an unconnected transport layer socket.
*/
static
vlc_tls_t
*
vlc_tls_SocketAddrInfo
(
const
struct
addrinfo
*
restrict
info
)
{
int
fd
=
vlc_socket
(
info
->
ai_family
,
info
->
ai_socktype
,
info
->
ai_protocol
,
true
/* nonblocking */
);
if
(
fd
==
-
1
)
return
NULL
;
setsockopt
(
fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
(
int
){
1
},
sizeof
(
int
));
if
(
info
->
ai_socktype
==
SOCK_STREAM
&&
info
->
ai_protocol
==
IPPROTO_TCP
)
setsockopt
(
fd
,
SOL_TCP
,
TCP_NODELAY
,
&
(
int
){
1
},
sizeof
(
int
));
vlc_tls_t
*
sk
=
vlc_tls_SocketAlloc
(
fd
,
info
->
ai_addr
,
info
->
ai_addrlen
);
if
(
unlikely
(
sk
==
NULL
))
net_Close
(
fd
);
return
sk
;
}
/**
* Waits for pending transport layer socket connection.
*/
static
int
vlc_tls_WaitConnect
(
vlc_tls_t
*
tls
)
{
const
int
fd
=
vlc_tls_GetFD
(
tls
);
struct
pollfd
ufd
;
ufd
.
fd
=
fd
;
ufd
.
events
=
POLLOUT
;
do
{
if
(
vlc_killed
())
{
errno
=
EINTR
;
return
-
1
;
}
}
while
(
vlc_poll_i11e
(
&
ufd
,
1
,
-
1
)
<=
0
);
int
val
;
socklen_t
len
=
sizeof
(
val
);
if
(
getsockopt
(
fd
,
SOL_SOCKET
,
SO_ERROR
,
&
val
,
&
len
))