You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
4.3 KiB
162 lines
4.3 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
|
|
#define RUN_MODE_UNUSED 1
|
|
#define RUN_MODE_USED 2
|
|
|
|
int is_invalid_errno()
|
|
{
|
|
switch (errno)
|
|
{
|
|
case EACCES:
|
|
case EADDRINUSE:
|
|
return 0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void usage(char* cmd)
|
|
{
|
|
fprintf(stderr, "Usage: %s <unused|used>\n"
|
|
"\tunused - Return unused random port and exit\n"
|
|
"\tused - Print a port that is being used, and hang on\n", cmd);
|
|
exit(3);
|
|
}
|
|
|
|
void alarm_signal_handler(int sig)
|
|
{
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
if (2 != argc)
|
|
{
|
|
usage(argv[0]);
|
|
}
|
|
int run_mode = 0;
|
|
if (!strcmp("unused", argv[1]))
|
|
{
|
|
run_mode = RUN_MODE_UNUSED;
|
|
}
|
|
else if (!strcmp("used", argv[1]))
|
|
{
|
|
run_mode = RUN_MODE_USED;
|
|
}
|
|
else
|
|
{
|
|
usage(argv[0]);
|
|
}
|
|
srand ((unsigned int)time(NULL));
|
|
do
|
|
{
|
|
int random_port = 0x400 + (rand() % 0xffff - 0x400); //Picks a random number from 1024 to 65535
|
|
struct sockaddr_in serv_addr;
|
|
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
memset(&serv_addr, 0, sizeof(serv_addr));
|
|
|
|
serv_addr.sin_family = AF_INET;
|
|
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
serv_addr.sin_port = htons(random_port);
|
|
if (0 != bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)))
|
|
{
|
|
close(listenfd);
|
|
if (is_invalid_errno())
|
|
{
|
|
perror("bind");
|
|
return 1;
|
|
}
|
|
continue;
|
|
}
|
|
if (0 != listen(listenfd, 1))
|
|
{
|
|
close(listenfd);
|
|
if (is_invalid_errno())
|
|
{
|
|
perror("listen");
|
|
return 2;
|
|
}
|
|
continue;
|
|
}
|
|
printf("%d\n", random_port);
|
|
fflush(stdout);
|
|
if (run_mode == RUN_MODE_USED)
|
|
{
|
|
/*
|
|
* User specified that he wants to get a TCP port that is being used.
|
|
* So, fork another process that will listen to this port and
|
|
* exit the original process so that the parent process (make) can
|
|
* continue.
|
|
*/
|
|
pid_t ppid = getppid(); //ppid is the process ID of "make"
|
|
pid_t pid = fork();
|
|
if (pid < 0)
|
|
{
|
|
perror("fork");
|
|
return 4;
|
|
}
|
|
if (pid > 0)
|
|
{
|
|
//After we printed the random port to STDOUT, the parent process
|
|
//(make) can continue
|
|
exit(0);
|
|
}
|
|
int count = 60;
|
|
// Hang on while ppid is still running
|
|
while (kill(ppid, 0) == 0)
|
|
{
|
|
socklen_t length;
|
|
struct sockaddr dummy;
|
|
struct sigaction saction;
|
|
if (count-- <= 0)
|
|
{
|
|
break;
|
|
}
|
|
memset(&saction, 0, sizeof(saction));
|
|
//We don't want the default SIGALRM behavior (i.e. kill the process)
|
|
saction.sa_handler = alarm_signal_handler;
|
|
//Enables SIGALRM to interrupt accept()
|
|
sigaction(SIGALRM, &saction, NULL);
|
|
alarm(1);
|
|
int newfd = accept(listenfd, &dummy, &length);
|
|
if (newfd < 0)
|
|
{
|
|
if (EINTR != errno)
|
|
{
|
|
perror("accept");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
close(newfd);
|
|
}
|
|
}
|
|
}
|
|
close(listenfd);
|
|
}
|
|
while (0);
|
|
|
|
return 0;
|
|
}
|