mirror of
https://github.com/kingk85/uFTP.git
synced 2025-07-17 09:16:11 +03:00
fix: pasv port chosen after availability checks
This commit is contained in:
@ -123,6 +123,8 @@ void *connectionWorkerHandle(cleanUpWorkerArgs *args)
|
||||
|
||||
// Enable cancellation for this thread
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
|
||||
|
||||
pthread_cleanup_push(workerCleanup, args);
|
||||
ftpData->clients[theSocketId].workerData.threadIsAlive = 1;
|
||||
ftpData->clients[theSocketId].workerData.threadHasBeenCreated = 1;
|
||||
|
57
ftpData.c
57
ftpData.c
@ -257,28 +257,45 @@ void appendToDynamicStringDataType(dynamicStringDataType *dynamicString, char *t
|
||||
|
||||
void setRandomicPort(ftpDataType *data, int socketPosition)
|
||||
{
|
||||
unsigned short int randomicPort = 5000;
|
||||
int i = 0;
|
||||
unsigned short int randomicPort;
|
||||
int maxAttempts = data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin +1;
|
||||
int attempt = 0;
|
||||
int conflict;
|
||||
|
||||
randomicPort = data->ftpParameters.connectionPortMin + (rand()%(data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin));
|
||||
while (attempt++ < maxAttempts)
|
||||
{
|
||||
// Generate a random port in range
|
||||
randomicPort = data->ftpParameters.connectionPortMin +
|
||||
(rand() % (data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin + 1));
|
||||
|
||||
while (i < data->ftpParameters.maxClients)
|
||||
// Check against other clients
|
||||
conflict = 0;
|
||||
for (int i = 0; i < data->ftpParameters.maxClients; ++i)
|
||||
{
|
||||
if (randomicPort == data->clients[i].workerData.connectionPort)
|
||||
if (i != socketPosition &&
|
||||
data->clients[i].workerData.connectionPort == randomicPort)
|
||||
{
|
||||
randomicPort = data->ftpParameters.connectionPortMin + (rand()%(data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin));
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
conflict = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (conflict)
|
||||
continue;
|
||||
|
||||
// Check if port is in use on the system
|
||||
if (!isPortInUse(randomicPort))
|
||||
{
|
||||
data->clients[socketPosition].workerData.connectionPort = randomicPort;
|
||||
my_printf("\n data->clients[%d].workerData.connectionPort = %d",
|
||||
socketPosition, randomicPort);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my_printf("\n data->clients[%d].workerData.connectionPort = %d", socketPosition, data->clients[socketPosition].workerData.connectionPort);
|
||||
|
||||
// If we’re here, we failed to find a port
|
||||
addLog("Failed to find available random port", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
data->clients[socketPosition].workerData.connectionPort = 0;
|
||||
}
|
||||
|
||||
int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumber, int commandType, DYNMEM_MemoryTable_DataType **memoryTable)
|
||||
@ -676,15 +693,23 @@ void deleteListDataInfoVector(DYNV_VectorGenericDataType *theVector)
|
||||
void cancelWorker(ftpDataType *data, int clientId)
|
||||
{
|
||||
void *pReturn;
|
||||
addLog("Cancelling thread because is busy", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
|
||||
if (data->clients[clientId].workerData.threadHasBeenCreated) {
|
||||
addLog("Cancelling thread because it is busy", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
|
||||
int returnCode = pthread_cancel(data->clients[clientId].workerData.workerThread);
|
||||
if (returnCode != 0)
|
||||
{
|
||||
if (returnCode != 0) {
|
||||
addLog("Cancelling thread ERROR", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
}
|
||||
|
||||
returnCode = pthread_join(data->clients[clientId].workerData.workerThread, &pReturn);
|
||||
if (returnCode != 0) {
|
||||
addLog("Joining thread ERROR", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
}
|
||||
|
||||
data->clients[clientId].workerData.threadHasBeenCreated = 0;
|
||||
data->clients[clientId].workerData.workerThread = 0; // Reset thread ID
|
||||
}
|
||||
}
|
||||
|
||||
void resetWorkerData(ftpDataType *data, int clientId, int isInitialization)
|
||||
|
@ -360,6 +360,38 @@ int getMaximumSocketFd(int mainSocket, ftpDataType * ftpData)
|
||||
|
||||
#ifdef IPV6_ENABLED
|
||||
|
||||
int isPortInUse(int port) {
|
||||
int sockfd;
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
perror("socket");
|
||||
return 1; // Assume port is in use if we can't create a socket
|
||||
}
|
||||
|
||||
int reuse = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
addr.sin6_addr = in6addr_any;
|
||||
|
||||
int result = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
|
||||
close(sockfd); // Always close after test
|
||||
|
||||
if (result == 0) {
|
||||
return 0; // Port is free
|
||||
} else if (errno == EADDRINUSE) {
|
||||
return 1; // Port is in use
|
||||
} else {
|
||||
perror("bind");
|
||||
return 1; // Other error, treat as in-use
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int createSocket(ftpDataType * ftpData)
|
||||
{
|
||||
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
|
||||
@ -515,6 +547,37 @@ int createPassiveSocket(int port)
|
||||
|
||||
#else
|
||||
|
||||
int isPortInUse(int port) {
|
||||
int sockfd;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
perror("socket");
|
||||
return 1; // Assume port is in use if we can't create a socket
|
||||
}
|
||||
|
||||
int reuse = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
int result = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
|
||||
close(sockfd); // Always close after test
|
||||
|
||||
if (result == 0) {
|
||||
return 0; // Port is free
|
||||
} else if (errno == EADDRINUSE) {
|
||||
return 1; // Port is in use
|
||||
} else {
|
||||
perror("bind");
|
||||
return 1; // Other error, treat as in-use
|
||||
}
|
||||
}
|
||||
|
||||
int createSocket(ftpDataType * ftpData)
|
||||
{
|
||||
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
|
||||
@ -582,21 +645,23 @@ int createSocket(ftpDataType * ftpData)
|
||||
int createPassiveSocket(int port)
|
||||
{
|
||||
int sock, returnCode;
|
||||
struct sockaddr_in temp;
|
||||
struct sockaddr_in serveraddr;
|
||||
int max_retries = 12; // number of bind retries
|
||||
int retry_delay_sec = 1; // delay between retries
|
||||
|
||||
//Socket creation
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock == -1)
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
perror("socket() failed");
|
||||
addLog("socket failed", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
return -1;
|
||||
}
|
||||
|
||||
temp.sin_family = AF_INET;
|
||||
temp.sin_addr.s_addr = INADDR_ANY;
|
||||
temp.sin_port = htons(port);
|
||||
memset(&serveraddr, 0, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
serveraddr.sin_port = htons(port);
|
||||
serveraddr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
int reuse = 1;
|
||||
|
||||
#ifdef SO_REUSEADDR
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
|
||||
{
|
||||
@ -609,37 +674,53 @@ int createPassiveSocket(int port)
|
||||
#ifdef SO_REUSEPORT
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
|
||||
{
|
||||
perror("setsockopt(SO_REUSEADDR) failed");
|
||||
my_printfError("setsockopt(SO_REUSEADDR) failed");
|
||||
perror("setsockopt(SO_REUSEPORT) failed");
|
||||
my_printfError("setsockopt(SO_REUSEPORT) failed");
|
||||
addLog("setsocketerror", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
}
|
||||
#endif
|
||||
|
||||
//Bind socket
|
||||
returnCode = bind(sock,(struct sockaddr*) &temp,sizeof(temp));
|
||||
|
||||
if (returnCode == -1)
|
||||
// Retry bind if it fails with EADDRINUSE
|
||||
for (int i = 0; i < max_retries; i++)
|
||||
{
|
||||
my_printf("\n Could not bind %d errno = %d", sock, errno);
|
||||
|
||||
if (sock != -1)
|
||||
returnCode = bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
|
||||
if (returnCode == 0)
|
||||
{
|
||||
if (i > 0)
|
||||
printf("\n Success After: %d attempts", i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == EADDRINUSE)
|
||||
{
|
||||
my_printf("Bind failed with EADDRINUSE on port: %d, retrying %d/%d...\n", port, i + 1, max_retries);
|
||||
sleep(retry_delay_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("bind() failed");
|
||||
addLog("bind failed", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
//Number of client allowed
|
||||
if (returnCode != 0)
|
||||
{
|
||||
my_printf("Bind failed after %d retries, errno=%d\n", max_retries, errno);
|
||||
addLog("bind failed after all attempts!", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Start listening
|
||||
returnCode = listen(sock, 1);
|
||||
|
||||
if (returnCode == -1)
|
||||
{
|
||||
addLog("listen failed", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||
my_printf("\nCould not listen %d errno = %d", sock, errno);
|
||||
if (sock != -1)
|
||||
{
|
||||
close(sock);
|
||||
}
|
||||
return returnCode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
Reference in New Issue
Block a user