Question

I want to connect to a remote server using a specific local port, not one assigned randomly by the kernel. I can do this by calling bind() to bind to the local port before calling connect() to the remote server.

My question is what happens if the local port I want to use is already in use by another application? I should be able to use it anyway, provided the destination or remote port are different (the same way a server can accept() multiple connections on port 80). But shouldn't my bind call fail in this case, and if so how can I set up the socket to use the local port that's already in use by another application?

The reason I want to do this is I am trying to write a local proxy that connects to a server application who checks the source port. If the source port is wrong the server won't allow the connection. The client side application connects to my proxy, and I want my proxy to use the same port to connect to the server - but if the proxy is on the same machine it won't work because the port is already in use by the application connecting to my proxy.

Was it helpful?

Solution

You can make an argument that you should be able to use it anyway, but TCP implementations don't let you unless the two binds are different. For example, you are probably able to bind to the same port with different IP addresses.

There are two problems with permitting overlapping binds:

  1. What happens if both applications call accept? Do they fight over incoming connections?

  2. What happens if both applications try to make an outbound connection to the same IP and port? How can those two connections be distinguished?

Now these problems could be solved. But I don't know of any implementations that bother. The argument is that the applications would have to cooperate or they would get surprising results. And if they're cooperating, they can share the bound socket.

So the answer is: If you aren't cooperating with the other application that has the port, then you have no right to share it. If you are cooperating with the other application, ask it to give you a copy of its socket using the method your platform supports.

OTHER TIPS

> But shouldn't my bind call fail in this case,

Yes if the socket does not have SO_REUSEADDR option set.

> and if so how can I set up the socket to use the local port that's already in use by another application?

Both your application and another application must set SO_REUSEADDR option on the socket, which wants to bind to the local port.

The code below connects to the HTTP server, given as command-line argument, from port 1111:

#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>

#define CLIENT_PORT 1111
#define SERVER_PORT 80

int main(int argc, char *argv[]) {

  struct sockaddr_in client_name, server_name;
  struct hostent *server_info;

  if (argc != 2)
    return printf("Exactly one argument is required: host to connect\n"), 1;

  int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (sock_fd < 0)
    return perror("socket"), 1;

  /* Without the next 4 lines, bind refuses to use the same port */
  int reuseaddr = 1;
  if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
                 sizeof(reuseaddr)) < 0)
    return perror("setsockopt"), 1;

  client_name.sin_family = AF_INET;
  client_name.sin_port = htons(CLIENT_PORT);
  client_name.sin_addr.s_addr = htonl(INADDR_ANY);

  if (bind(sock_fd, (struct sockaddr *) &client_name, 
           sizeof(struct sockaddr_in)) < 0)
    return perror("bind"), 1;

  server_name.sin_family = AF_INET;
  server_name.sin_port = htons(SERVER_PORT);
  if ((server_info = gethostbyname(argv[1])) == NULL)
    return printf("Unknown host: %s\n", argv[1]), 1;

  server_name.sin_addr = *(struct in_addr *) server_info->h_addr;

  if (connect(sock_fd, (struct sockaddr *) &server_name, 
              sizeof(server_name)) < 0)
    return perror("connect"), 1;

  return 0;
}

> what happens if the local port I want to use is already in use by another application?

Without SO_REUSEADDR (try to comment out the 4 lines around setsockopt), bind fails:

$ ./client google.com
$ ./client stackoverflow.com
bind: Address already in use

With SO_REUSEADDR, you can connect to different remote servers:

$ ./client google.com
$ ./client stackoverflow.com

But then connect will not allow you to open two sockets with same source and destinations:

$ ./client google.com
$ ./client google.com
connect: Cannot assign requested address

bind knows just one endpoint.

Suppose that two sockets are bound to the same port. Which one the incoming packet shall be routed to?

accept on the other hand knows both peers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top