I am trying to get a DTLS "connection" going using OpenSSL 1.1.1.
I am constantly getting a SSL_ERROR_SYSCALL when trying to run DTLSv1_listen() on the socket.
I use a single AF_INET, DGRAM, UDP socket to receive all incoming data. I assumed I could leave it at that and OpenSSL would take care of determining the sender whenever a datagram is received but I am starting to think I am mistaken.
I have: (error handling omitted for brevity)
SSL_CTX *ctx = SSL_CTX_new(DTLS());
SSL_CTX_use_certificate_file(ctx, "certs/server-cert.pem", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, "certs/server-key.pem", SSL_FILETYPE_PEM);
SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx, &verify_cookie);
int fd = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on));
bind(fd, (const struct sockaddr *) &server_addr, sizeof(struct sockaddr_in))
SSL *ssl = SSL_new(ctx);
SSL_set_fd(ssl, fd);
SSL_set_accept_state(ssl);
while(DTLSv1_listen(ssl, (BIO_ADDR *) BIO_get_conn_address(SSL_get_rbio(ssl))) <= 0)
...
As I mentioned, that last line gives me an `SSL_ERROR_SYSCALL'.
errno gives me 0.
I suspect I'm missing some steps in the CTX configuration but I'm not sure what.
I've been looking through some examples and one in particular caught my eye. It seems to create a new socket whenever it receives a datagram and does a connect() on that socket to the remote address. This seems a bit ridicuous to me as I don't think UDP requires a soket per client AFAIK.
According connect with UDP
In BSD sockets one can do a connect on a UDP socket, but this
basically just sets the default destination address for send (instead
giving explicitly to send_to).
So the success may depent on the used send function.
Generally you can use a UDP socket for DTLS communication to many peers. That requires some mapping between the "association keys/seqn-numbers" and the other peer's address. Though this is pretty much the same as on the server side, it should not be impossible. However, a lot of TLS-derived implementations don't enabled such UDP specific features and so you may be forced to use separate sockets.
One pitfall will be left anyway:
If you want to use SNI /server Name Indication) to access the same physical server using different dns names from the same peer, then you will fail.
The following is the essence of my test fixture -
SetUp()
{
g_listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
/* localhost is the server */
bind(g_listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(g_listen_sock, max_connections);
}
testcase()
{
hdl = accept(g_listen_sock, NULL, NULL);
-- send()/recv() data on the socket --
}
TearDown()
{
shutdown(g_listen_sock, SHUT_RDWR);
close(g_listen_sock);
g_listen_sock = INVALID_SOCKET;
}
In the normal use of the application the listening socket is bound only once during the lifetime of the application, however the test setup repeatedly opens and closes the listening socket. The first iteration of the testcase works fine but subsequent iterations fail at the bind() call with errno == 98 i.e. EADDRINUSE.
How do I avoid this situation? The solution ideally wouldn't require me to have a separate test version of the code, for e.g. using SO_REUSEADDR while testing.
P.S. - the same code works fine on Windows, the bind() failure happens on Linux.
What you are trying to get around is a built-in functionality of the TCP layer of networking. The linux kernel will not allow you to rebind that socket because the closed socket will be in the TIME_WAIT state. There is nothing you can do to circumvent that besides using SO_REUSEADDR (as you have already pointed out), or by using a different port for each test which it doesn't sound like you want to do either.
Unfortunately, TCP was not designed to close and open the same IP/port multiple times in a row for testing, so you will have to pick your poison if you still want to do this kind of testing.
Also see this answer for a more in-depth exploration of your problem.
I am doing raw socket programming in C. I am creating my own ethernet, ip and tcp headers. Then I add data to the packet and send it. Then I need to wait for response from the other program.
I have one computer. So using lo as my interface. I have something like
CreateSocket
BindSocketToInterface
Sendto
recvfrom
Now it is receiving it's own data which is undesirable. So I am thinking to bind socket to specific address.
Can I do it?
Also How to do it??
Can select solve this problem ??
Thanks :)
Like if you want interface then as follows
char *opt;
opt = "eth0";
setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, 4);
But if you want port address then
You cannot bind a raw socket to a specific port because "port" is a concept in TCP and UDP, not IP. Look at the header diagrams for those three protocols and it should become obvious: you are working at a lower level, where the concept of port is not known.
you can use setsockopt to bind it to a specific device.
struct ifreq *ifr = <populate some values>;
setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)ifr, sizeof(struct ifreq))
Try the above code and it should work. populate the ifreq correctly for the required network device.
I've been stuck with this problem for days and I really cannot figure out where this comes from.
I'm doing a program communicating through UDP. I'm using the sendto() method to communicate between programs. Also, there is a UI TCP socket opened and used by the user, managing the program through telnet. The telnet part is 100% working with other features of the program.
The problem is, when I'm using the sendto() method, the program blocks totally and the Telnet connection is broken (Communication has been cut by host, it says). My problem is that, as the program blocks, I cannot figure out why sendto() is failing because it wont execute what is after. Even with something like :
if(sendto(...)<0)
{
perror("Sendto error :");
}
nothing happens, I cannot get any information with errno. The fact that the telnet connection is broken seems weird to me because it is on a very different port and therefore shouldn't be interrupted like this.
I tried to set my UDP socket as non blocking but it still doesn't work. Here is the non working part of the code :
struct sockaddr_in address;
hp = gethostbyname(myaddr);
address.sin_family = AF_INET;
address.sin_port = htons(udp_port);
memcpy(&(address.sin_addr.s_addr), hp->h_addr, hp->h_length);
sendto(fd, buffer, buffer_size, 0, (struct sockaddr *)&address, sizeof(address));
close(fd);
Thanks in advance for your help and ask me if you want more specific informations.
I would like to establish an IPC connection between several processes on Linux. I have never used UNIX sockets before, and thus I don't know if this is the correct approach to this problem.
One process receives data (unformated, binary) and shall distribute this data via a local AF_UNIX socket using the datagram protocol (i.e. similar to UDP with AF_INET). The data sent from this process to a local Unix socket shall be received by multiple clients listening on the same socket. The number of receivers may vary.
To achieve this the following code is used to create a socket and send data to it (the server process):
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
// buf contains the data, buflen contains the number of bytes
int bytes = write(socket, buf, buflen);
...
close(socket);
unlink(ipcFile.sun_path);
This write returns -1 with errno reporting ENOTCONN ("Transport endpoint is not connected"). I guess this is because no receiving process is currently listening to this local socket, correct?
Then, I tried to create a client who connects to this socket.
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
char buf[1024];
int bytes = read(socket, buf, sizeof(buf));
...
close(socket);
Here, the bind fails ("Address already in use"). So, do I need to set some socket options, or is this generally the wrong approach?
Thanks in advance for any comments / solutions!
There's a trick to using Unix Domain Socket with datagram configuration. Unlike stream sockets (tcp or unix domain socket), datagram sockets need endpoints defined for both the server AND the client. When one establishes a connection in stream sockets, an endpoint for the client is implicitly created by the operating system. Whether this corresponds to an ephemeral TCP/UDP port, or a temporary inode for the unix domain, the endpoint for the client is created for you. Thats why you don't normally need to issue a call to bind() for stream sockets in the client.
The reason you're seeing "Address already in use" is because you're telling the client to bind to the same address as the server. bind() is about asserting external identity. Two sockets can't normally have the same name.
With datagram sockets, specifically unix domain datagram sockets, the client has to bind() to its own endpoint, then connect() to the server's endpoint. Here is your client code, slightly modified, with some other goodies thrown in:
char * server_filename = "/tmp/socket-server";
char * client_filename = "/tmp/socket-client";
struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, server_filename, 104); // XXX: should be limited to about 104 characters, system dependent
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sun_family = AF_UNIX;
strncpy(client_addr.sun_path, client_filename, 104);
// get socket
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
// bind client to client_filename
bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr));
// connect client to server_filename
connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
...
char buf[1024];
int bytes = read(sockfd, buf, sizeof(buf));
...
close(sockfd);
At this point your socket should be fully setup. I think theoretically you can use read()/write(), but usually I'd use send()/recv() for datagram sockets.
Normally you'll want to check error after each of these calls and issue a perror() afterwards. It will greatly aid you when things go wrong. In general, use a pattern like this:
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
}
This goes for pretty much any C system calls.
The best reference for this is Steven's "Unix Network Programming". In the 3rd edition, section 15.4, pages 415-419 show some examples and lists many of the caveats.
By the way, in reference to
I guess this is because no receiving process is currently listening to this local socket, correct?
I think you're right about the ENOTCONN error from write() in the server. A UDP socket would normally not complain because it has no facility to know if the client process is listening. However, unix domain datagram sockets are different. In fact, the write() will actually block if the client's receive buffer is full rather than drop the packet. This makes unix domain datagram sockets much superior to UDP for IPC because UDP will most certainly drop packets when under load, even on localhost. On the other hand, it means you have to be careful with fast writers and slow readers.
The proximate cause of your error is that write() doesn't know where you want to send the data to. bind() sets the name of your side of the socket - ie. where the data is coming from. To set the destination side of the socket, you can either use connect(); or you can use sendto() instead of write().
The other error ("Address already in use") is because only one process can bind() to an address.
You will need to change your approach to take this into account. Your server will need to listen on a well-known address, set with bind(). Your clients will need to send a message to the server at this address to register their interest in receiving datagrams. The server will recieve the registration messages from clients using recvfrom(), and record the address used by each client. When it wants to send a message, it will have to loop over all the clients it knows about, using sendto() to send the message to each one in turn.
Alternatively, you could use local IP multicast instead of UNIX domain sockets (UNIX domain sockets don't support multicast).
If the question intended to be about broadcasting (as I understand it), then according to unix(4) - UNIX-domain protocol family, broadcasting it is not available with UNIX Domain Sockets:
The Unix Ns -domain protocol family does not support
broadcast addressing or any form of "wildcard" matching
on incoming messages. All addresses are absolute- or
relative-pathnames of other Unix Ns -domain sockets.
May be multicast could be an option, but I feel to know it's not available with POSIX, although Linux supports UNIX Domain Socket multicast.
Also see: Introducing multicast Unix sockets.
It will happen because of
server or client die before unlink/remove for bind() file associate.
any of client/server using this bind path, try to run server again.
solutions :
when you want to bind again just check that file is already associate then unlink that file.
How to step :
first check access of this file by access(2);
if yes then unlink(2) it.
put this peace of code before bind() call,position is independent.
if(!access(filename.c_str()))
unlink(filename.c_str());
for more reference read unix(7)
Wouldn't it be easier to use shared memory or named pipes? A socket is a connection between two processes (on the same or a different machine). It isn't a mass communication method.
If you want to give something to multiple clients, you create a server that waits for connections and then all the clients can connect and it gives them the information. You can accept concurrent connections by making the program multi-threaded or by forking processes. The server establishes multiple socket-based connections with multiple clients, rather than having one socket that multiple clients connect to.
You should look into IP multicasting instead of Unix-domain anything. At present you are just trying to write to nowhere. And if you connect to one client you will only be writing to that client.
This stuff doesn't work the way you seem to think it does.
You can solve the bind error with the following code:
int use = yesno;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&use, sizeof(int));
With UDP protocol, you must invoke connect() if you want to use write() or send(), otherwise you should use sendto() instead.
To achieve your requirements, the following pseudo code may be of help:
sockfd = socket(AF_INET, SOCK_DGRAM, 0)
set RESUSEADDR with setsockopt
bind()
while (1) {
recvfrom()
sendto()
}