-
Bind to a local port that is already in use
Hi,
(Development Environment => OS: Windows Vista, Compiler: Visual C++ 2005 Express Edition)
I MUST have two independent applications which use to same local port by UDP. The application 1 is a server which receives the UDP request, processes it, and sends the response. The application 2 is a sender which sends UDP packets to clients.
So, In application 2, I write the following statements between socket and bind functions:
Code:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
int iOptVal;
int iOptLen = sizeof(int);
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen) != SOCKET_ERROR) {
printf("Set SO_REUSEADD: ON\n");
}
if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) {
printf("SO_REUSEADD Value: %ld\n", iOptVal);
}
I run the application 1, and then run the application 2.
In application 2, it shows:
Set SO_REUSEADD: ON
SO_REUSEADD Value: 1
Can't bind a socket with error code 10013
I run the application 2, and then run the application 1.
In application 1, it occurs an error on bind statement about [Address already in use : 10048].
I also write the following statements between socket and bind functions in application 1:
Code:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
int iOptVal = 0;
int iOptLen = sizeof(int);
if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) {
printf("SO_REUSEADD Value: %ld\n", iOptVal);
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen) != SOCKET_ERROR) {
printf("Set SO_REUSEADD: ON\n");
}
if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) {
printf("SO_REUSEADD Value: %ld\n", iOptVal);
}
I get the following result and no error occurs.
SO_REUSEADD Value: 0
Set SO_REUSEADD: ON
SO_REUSEADD Value: 1
Is this way right? :)
Thank you.
-
Re: Bind to a local port that is already in use
your usage of the setsockopt function is correct, however, you can't have 2 applications using the same local port.
Why do you need them to use the same port? Do both act as servers, i. e. do they get messages from clients and then answer to them? If so, you should think of using different ports. And if they are not designed as servers, it does not matter what local port they use.
HTH
Richard
-
Re: Bind to a local port that is already in use
setsockopt is for operating system to free your socket immediately when the socket status is closing.so,there is no time_waitting status for your socket.please reference for some books about TCP protocol
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by Richard.J
your usage of the setsockopt function is correct, however, you can't have 2 applications using the same local port.
Why do you need them to use the same port? Do both act as servers, i. e. do they get messages from clients and then answer to them? If so, you should think of using different ports. And if they are not designed as servers, it does not matter what local port they use.
HTH
Richard
In MSDN, it says
Since every connection is uniquely identified by the combination of local and remote addresses, there is NO problem with having two sockets bound to the same local address as long as the remote addresses are different..
But I use the same remote addresses, it seems to be okay in my testing.
-
Re: Bind to a local port that is already in use
But it's against the TCP protocol. We have a daemon running on port 100 right and that daemon understands some protocol X, but in the mean time if we run another daemon that binds also on port 100 and understands protocol Y what would happen? That's why modern OSs have a security mechanism to disallow binding on the same port twice.
You can take the code from one of your daemons and implement it in the other so you'll have one "super" daemon understanding both protocols.
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by ludakot
But it's against the TCP protocol. We have a daemon running on port 100 right and that daemon understands some protocol X, but in the mean time if we run another daemon that binds also on port 100 and understands protocol Y what would happen? That's why modern OSs have a security mechanism to disallow binding on the same port twice.
You can take the code from one of your daemons and implement it in the other so you'll have one "super" daemon understanding both protocols.
I know that:
For TCP, we are NEVER able to bind the same IP address and the same port, a completely duplicate binding.
But for UDP, I don't find any information about that.
-
Re: Bind to a local port that is already in use
Code:
home:~/udp# python 1.py &
[1] 23109
home:~/udp# python 1.py &
[2] 23110
home:~/udp# Traceback (most recent call last):
File "1.py", line 7, in ?
server.bind(('', PORT))
File "<string>", line 1, in bind
socket.error: (98, 'Address already in use')
[2]+ Exit 1 python 1.py
home:~/udp# cat 1.py
import socket
PORT = 10000
BUFLEN = 512
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
server.bind(('', PORT))
while True:
(message, address) = server.recvfrom(BUFLEN)
print 'Received packet from %s:%d' % (address[0], address[1])
print 'Data: %s' % message
There's your answer :)
To answer simple, you can't have the same door number in the same hallway :)
-
Re: Bind to a local port that is already in use
Cooker is looking for C/C++ answers for Windows Vista. What are you hoping to prove with your python posting?
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by MikeAThon
Cooker is looking for C/C++ answers for Windows Vista. What are you hoping to prove with your python posting?
Proving that you can't bind on the same UDP port on the same IP twice.
OSs don't matter the protocol is the same on *any* OS otherwise *nix machines can't communicate with windows machines over the internet :)
Programming language also doesn't matter because sockets are sockets, implemented in the OS.
If anyone can prove otherwise I will erase my name off my CCNA certificate and place his name instead.
-
Re: Bind to a local port that is already in use
I make two experiments:
- Two UDP sockets bind the same local address and port, send UDP packets to the SAME remote address for every 1 second.
- Two UDP sockets bind the same local address and port, receive UDP packets.
Programs in experiments, they calls setsockopt function to set the SO_REUSEADDR socket option for the socket before issuing the bind.
In the experiment 1, at the remote address side, I can receive all the UDP packets.
In the experiment 2, the socket which it is the first to bind will receive the UDP traffic.
I am sure that sockets which bind to the same local port and address can send UDP packets correctly.
That's all my experiments.
-
Re: Bind to a local port that is already in use
Those are good experiments. Thank you for sharing your results with us.
Mike
-
Re: Bind to a local port that is already in use
I've made Cooker's experiment #2 with TCP sockets once and it was absolutely arbitrary which server received packets. (Just wanted to let you know.)
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by ludakot
... you can't bind on the same UDP port on the same IP twice.
...
If anyone can prove otherwise I will erase my name off my CCNA certificate and place his name instead.
@ludakot: In view of Cooker's experiments on UDP, and Richard.J's confirmation for TCP, are you ready to relinquish that CCNA certificate?
Just teasing ;) Sorry, I couldn't resist.
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by MikeAThon
@ludakot: In view of Cooker's experiments on UDP, and Richard.J's confirmation for TCP, are you ready to relinquish that CCNA certificate?
Just teasing ;) Sorry, I couldn't resist.
I'll believe it when I see some running code. If that's so then apparently windows sockets have huge security issue. What stops user to bind on port 80 on some webserver and steal HTTP based usernames and passwords if it's arbitrary which server receives packets?
I don't have a windows machine to test this on, but every attempt i've done on my gentoo box has failed at the same place, I couldn't bind on the same port twice, not matter if it's UDP or TCP.
-
Re: Bind to a local port that is already in use
Yes, it is a security issue, but it's not unique to Windows. The issue arises in all BSD socket implementations that support the SO_REUSEADDR option. AFAIK, all implementations do so, inclusive of Linux, Sun etc.
Windows introduced the SO_EXCLUSIVEADDRUSE option to address this issue. See "Using SO_EXCLUSIVEADDRUSE" at http://msdn2.microsoft.com/en-us/library/ms740618.aspx . Here's a quote:
Quote:
The SO_EXCLUSIVEADDRUSE option prevents other sockets from being forcibly bound to the same address and port, a practice enabled by the SO_REUSEADDR option; such reuse can be executed by malicious applications to disrupt the application. The SO_EXCLUSIVEADDRUSE option is very useful to system services requiring high availability. This option is available on Microsoft Windows. The following code example illustrates setting this option.
I am not certain if other socket implementations (i.e., other than that on Windows) also have the SO_EXCLUSIVEADDRUSE option.
Mike
-
Re: Bind to a local port that is already in use
I also make the first experiment on Ubuntu Linux. The result is the same as on Windows Vista. I just share this information.
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by Cooker
I also make the first experiment on Ubuntu Linux. The result is the same as on Windows Vista. I just share this information.
Are you willing to share the source code so I can try it myself on gentoo?
-
Re: Bind to a local port that is already in use
Well, it's only security issue if you do TCP bind to ANY address. If you bind to a specific address, no other TCP server can "steal" that specific address+port.
Quote:
Originally Posted by MikeAThon
Yes, it is a security issue, but it's not unique to Windows. The issue arises in all BSD socket implementations that support the SO_REUSEADDR option. AFAIK, all implementations do so, inclusive of Linux, Sun etc.
Windows introduced the SO_EXCLUSIVEADDRUSE option to address this issue. See "Using SO_EXCLUSIVEADDRUSE" at
http://msdn2.microsoft.com/en-us/library/ms740618.aspx . Here's a quote:
I am not certain if other socket implementations (i.e., other than that on Windows) also have the SO_EXCLUSIVEADDRUSE option.
Mike
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by j0nas
Well, it's only security issue if you do TCP bind to ANY address. If you bind to a specific address, no other TCP server can "steal" that specific address+port.
I don't think I agree. The entire purpose of the SO_EXCLUSIVEADDR option is to prevent a malicious program from "stealing" the addr+port. Without SO_EXCLUSIVEADDR, it's my understanding that a malicious program can do exactly that:
Quote:
Originally Posted by http://msdn2.microsoft.com/en-us/library/ms740618.aspx
... such reuse can be executed by malicious applications to disrupt the application
.
-
Re: Bind to a local port that is already in use
Still waiting on that source code. I'm either doing something wrong or my OS has some security mechanism such as SO_EXCLUSIVEADDR at kernel level or something.
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by ludakot
Are you willing to share the source code so I can try it myself on gentoo?
At first, You can run the following source code on Windows OS.
- UDP Receiver
Code:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h> // for Winsock
#pragma comment(lib,"Ws2_32.lib") // for Winsock
void ErrExit(SOCKET fd, const char *format, ...);
int main(int argc, char *argv[])
{
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
int err = 0;
SOCKET sockfd = 0;
struct sockaddr_in local, remote;
int localport = 0;
int nrecvbytes = 0, fromlen = 0;
char recvbuf[128];
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
if (argc != 3) {
printf("Usage:\n");
printf(" program local_addr local_port\n");
printf("Description:\n");
printf(" Receive UDP packets from local_addr:local_port\n");
return -1;
}
localport = strtol(argv[2], NULL, 10);
// Initiate use of the Winsock DLL
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
// Could not find a usable WinSock DLL
printf("Couldn't find a usable WinSock DLL.\n");
return -1;
}
// Confirm that the WinSock DLL supports 2.2.
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
ErrExit(0, "Bad winsock version.\n");
// Create a socket that is bound to a specific transport service provider
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == INVALID_SOCKET)
ErrExit(0, "Can't open a socket with error code %d\n", WSAGetLastError());
// Contain information about local IP address and port
local.sin_family = AF_INET;
local.sin_port = htons(localport);
local.sin_addr.s_addr = inet_addr(argv[1]);
memset(local.sin_zero, '\0', sizeof local.sin_zero);
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen) == SOCKET_ERROR) {
printf("Can't set SO_REUSEADDR option.\n");
}
// Associate a local address with a socket
err = bind(sockfd, (struct sockaddr *)&local, sizeof local);
if (err == SOCKET_ERROR)
ErrExit(sockfd, "Can't bind to a local address and port with error code %d\n", WSAGetLastError());
memset(&remote, 0, sizeof remote);
memset(recvbuf, 0, sizeof recvbuf);
for (;;)
{
fromlen = sizeof remote;
nrecvbytes = recvfrom(sockfd, recvbuf, sizeof recvbuf, 0, (struct sockaddr *)&remote, &fromlen);
if (nrecvbytes == SOCKET_ERROR)
ErrExit(sockfd, "Can't receive messages with error code %d\n", WSAGetLastError());
recvbuf[nrecvbytes] = '\0';
printf("Message [%s] from %s:%d\n", recvbuf, inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
}
return 0;
}
void ErrExit(SOCKET fd, const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
if (fd != NULL)
closesocket(fd);
WSACleanup();
exit(1);
}
- UDP sender
Code:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <winsock2.h> // for Winsock
#pragma comment(lib,"Ws2_32.lib") // for Winsock
void ErrExit(SOCKET fd, const char *format, ...);
void wait(int seconds);
int main(int argc, char *argv[])
{
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
int err = 0;
SOCKET sockfd = 0;
struct sockaddr_in local, remote;
int localport = 0, remoteport = 0, cycle = 0;
int nsentbytes = 0;
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
if (argc != 7) {
printf("Usage:\n");
printf(" program local_addr local_port cycle message remote_addr remote_port\n");
printf("Description:\n");
printf(" Send a UDP packet to remote_addr:remote_port from local_addr:local_port every cycle seconds\n");
return -1;
}
localport = strtol(argv[2], NULL, 10);
remoteport = strtol(argv[6], NULL, 10);
cycle = strtol(argv[3], NULL, 10);
// Initiate use of the Winsock DLL
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
// Could not find a usable WinSock DLL
printf("Couldn't find a usable WinSock DLL.\n");
return -1;
}
// Confirm that the WinSock DLL supports 2.2.
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
ErrExit(0, "Bad winsock version.\n");
// Create a socket that is bound to a specific transport service provider
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == INVALID_SOCKET)
ErrExit(0, "Can't open a socket with error code %d\n", WSAGetLastError());
// Contain information about local IP address and port
local.sin_family = AF_INET;
local.sin_port = htons(localport);
local.sin_addr.s_addr = inet_addr(argv[1]);
memset(local.sin_zero, '\0', sizeof local.sin_zero);
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen) == SOCKET_ERROR) {
printf("Can't set SO_REUSEADDR option.\n");
}
// Associate a local address with a socket
err = bind(sockfd, (struct sockaddr *)&local, sizeof local);
if (err == SOCKET_ERROR)
ErrExit(sockfd, "Can't bind to a local address and port with error code %d\n", WSAGetLastError());
// Contain information about remote IP address and port
remote.sin_family = AF_INET;
remote.sin_port = htons(remoteport);
remote.sin_addr.s_addr = inet_addr(argv[5]);
memset(remote.sin_zero, '\0', sizeof remote.sin_zero);
printf("==> Press any key to quit the program. <==\n");
for (;;)
{
if (kbhit())
break;
nsentbytes = sendto(sockfd, argv[4], strlen(argv[4]), 0, (struct sockaddr *)&remote, sizeof remote);
if (nsentbytes == SOCKET_ERROR)
ErrExit(sockfd, "Can't send meesages to remote address with error code%d\n", WSAGetLastError());
wait(cycle);
}
system("pause");
return 0;
}
void ErrExit(SOCKET fd, const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
if (fd != NULL)
closesocket(fd);
WSACleanup();
system("pause");
exit(1);
}
void wait(int seconds)
{
clock_t endwait;
endwait = clock () + seconds * CLK_TCK ;
while (clock() < endwait) {}
}
The source code which runs on Ubuntu Linux isn't in my current PC. I will post later.
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by ludakot
Still waiting on that source code. I'm either doing something wrong or my OS has some security mechanism such as SO_EXCLUSIVEADDR at kernel level or something.
This SO_EXCLUSIVEADDR option is available on Microsoft Windows. On a Linux, all the socket information is in the man page for socket in section 7. You can type "man 7 socket" to get all these goodies and find if there exists SO_EXCLUSIVEADDRUSE option. That's my way.
-
Re: Bind to a local port that is already in use
Quote:
Originally Posted by ludakot
Are you willing to share the source code so I can try it myself on gentoo?
Linux version.
The source code of UDP sender
Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define CLK_TCK CLOCKS_PER_SEC
void ErrExit(int fd, const char *format, ...);
void wait(int seconds);
int main(int argc, char *argv[])
{
int err = 0;
int sockfd = 0;
struct sockaddr_in local, remote;
int localport = 0, remoteport = 0, cycle = 0;
int nsentbytes = 0;
int optval;
if (argc != 7) {
printf("Usage:\n");
printf(" program local_addr local_port cycle message remote_addr remote_port\n");
printf("Description:\n");
printf(" Send a UDP packet to remote_addr:remote_port from local_addr:local_port every cycle seconds\n");
return -1;
}
localport = strtol(argv[2], NULL, 10);
remoteport = strtol(argv[6], NULL, 10);
cycle = strtol(argv[3], NULL, 10);
// Create a socket that is bound to a specific transport service provider
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == INVALID_SOCKET)
ErrExit(0, "Can't open a socket with error %s\n", strerror(errno));
// Contain information about local IP address and port
local.sin_family = AF_INET;
local.sin_port = htons(localport);
local.sin_addr.s_addr = inet_addr(argv[1]);
memset(local.sin_zero, '\0', sizeof local.sin_zero);
optval = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof optval) == SOCKET_ERROR) {
printf("Can't set SO_REUSEADDR option.\n");
}
// Associate a local address with a socket
err = bind(sockfd, (struct sockaddr *)&local, sizeof local);
if (err == SOCKET_ERROR)
ErrExit(sockfd, "Can't bind to a local address and port with error %s\n", strerror(errno));
// Contain information about remote IP address and port
remote.sin_family = AF_INET;
remote.sin_port = htons(remoteport);
remote.sin_addr.s_addr = inet_addr(argv[5]);
memset(remote.sin_zero, '\0', sizeof remote.sin_zero);
for (;;)
{
nsentbytes = sendto(sockfd, argv[4], strlen(argv[4]), 0, (struct sockaddr *)&remote, sizeof remote);
if (nsentbytes == SOCKET_ERROR)
ErrExit(sockfd, "Can't send meesages to remote address with error %s\n", strerror(errno));
wait(cycle);
}
return 0;
}
void ErrExit(int fd, const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
if (fd != NULL)
close(fd);
exit(1);
}
void wait(int seconds)
{
clock_t endwait;
endwait = clock () + seconds * CLK_TCK ;
while (clock() < endwait) {}
}
I use 'tcpdump' to check UDP message at remote PC side.