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
|
// Enable cancellation for this thread
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||||
|
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
|
||||||
|
|
||||||
pthread_cleanup_push(workerCleanup, args);
|
pthread_cleanup_push(workerCleanup, args);
|
||||||
ftpData->clients[theSocketId].workerData.threadIsAlive = 1;
|
ftpData->clients[theSocketId].workerData.threadIsAlive = 1;
|
||||||
ftpData->clients[theSocketId].workerData.threadHasBeenCreated = 1;
|
ftpData->clients[theSocketId].workerData.threadHasBeenCreated = 1;
|
||||||
|
77
ftpData.c
77
ftpData.c
@ -257,28 +257,45 @@ void appendToDynamicStringDataType(dynamicStringDataType *dynamicString, char *t
|
|||||||
|
|
||||||
void setRandomicPort(ftpDataType *data, int socketPosition)
|
void setRandomicPort(ftpDataType *data, int socketPosition)
|
||||||
{
|
{
|
||||||
unsigned short int randomicPort = 5000;
|
unsigned short int randomicPort;
|
||||||
int i = 0;
|
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;
|
||||||
if (randomicPort == data->clients[i].workerData.connectionPort)
|
for (int i = 0; i < data->ftpParameters.maxClients; ++i)
|
||||||
{
|
{
|
||||||
randomicPort = data->ftpParameters.connectionPortMin + (rand()%(data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin));
|
if (i != socketPosition &&
|
||||||
i = 0;
|
data->clients[i].workerData.connectionPort == randomicPort)
|
||||||
}
|
{
|
||||||
else
|
conflict = 1;
|
||||||
{
|
break;
|
||||||
i++;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
data->clients[socketPosition].workerData.connectionPort = randomicPort;
|
if (conflict)
|
||||||
|
continue;
|
||||||
|
|
||||||
my_printf("\n data->clients[%d].workerData.connectionPort = %d", socketPosition, data->clients[socketPosition].workerData.connectionPort);
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumber, int commandType, DYNMEM_MemoryTable_DataType **memoryTable)
|
||||||
@ -675,16 +692,24 @@ void deleteListDataInfoVector(DYNV_VectorGenericDataType *theVector)
|
|||||||
|
|
||||||
void cancelWorker(ftpDataType *data, int clientId)
|
void cancelWorker(ftpDataType *data, int clientId)
|
||||||
{
|
{
|
||||||
void *pReturn;
|
void *pReturn;
|
||||||
addLog("Cancelling thread because is busy", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
|
||||||
int returnCode = pthread_cancel(data->clients[clientId].workerData.workerThread);
|
if (data->clients[clientId].workerData.threadHasBeenCreated) {
|
||||||
if (returnCode != 0)
|
addLog("Cancelling thread because it is busy", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||||
{
|
|
||||||
addLog("Cancelling thread ERROR", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
int returnCode = pthread_cancel(data->clients[clientId].workerData.workerThread);
|
||||||
|
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
|
||||||
}
|
}
|
||||||
returnCode = pthread_join(data->clients[clientId].workerData.workerThread, &pReturn);
|
|
||||||
|
|
||||||
data->clients[clientId].workerData.threadHasBeenCreated = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetWorkerData(ftpDataType *data, int clientId, int isInitialization)
|
void resetWorkerData(ftpDataType *data, int clientId, int isInitialization)
|
||||||
|
@ -360,6 +360,38 @@ int getMaximumSocketFd(int mainSocket, ftpDataType * ftpData)
|
|||||||
|
|
||||||
#ifdef IPV6_ENABLED
|
#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)
|
int createSocket(ftpDataType * ftpData)
|
||||||
{
|
{
|
||||||
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
|
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
|
||||||
@ -515,6 +547,37 @@ int createPassiveSocket(int port)
|
|||||||
|
|
||||||
#else
|
#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)
|
int createSocket(ftpDataType * ftpData)
|
||||||
{
|
{
|
||||||
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
|
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
|
||||||
@ -581,68 +644,86 @@ int createSocket(ftpDataType * ftpData)
|
|||||||
|
|
||||||
int createPassiveSocket(int port)
|
int createPassiveSocket(int port)
|
||||||
{
|
{
|
||||||
int sock, returnCode;
|
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
|
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
{
|
||||||
if (sock == -1)
|
perror("socket() failed");
|
||||||
{
|
addLog("socket failed", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp.sin_family = AF_INET;
|
memset(&serveraddr, 0, sizeof(serveraddr));
|
||||||
temp.sin_addr.s_addr = INADDR_ANY;
|
serveraddr.sin_family = AF_INET;
|
||||||
temp.sin_port = htons(port);
|
serveraddr.sin_port = htons(port);
|
||||||
|
serveraddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
int reuse = 1;
|
|
||||||
|
|
||||||
|
int reuse = 1;
|
||||||
#ifdef SO_REUSEADDR
|
#ifdef SO_REUSEADDR
|
||||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
|
||||||
{
|
{
|
||||||
perror("setsockopt(SO_REUSEADDR) failed");
|
perror("setsockopt(SO_REUSEADDR) failed");
|
||||||
my_printfError("setsockopt(SO_REUSEADDR) failed");
|
my_printfError("setsockopt(SO_REUSEADDR) failed");
|
||||||
addLog("setsocketerror", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
addLog("setsocketerror", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SO_REUSEPORT
|
#ifdef SO_REUSEPORT
|
||||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
|
||||||
{
|
{
|
||||||
perror("setsockopt(SO_REUSEADDR) failed");
|
perror("setsockopt(SO_REUSEPORT) failed");
|
||||||
my_printfError("setsockopt(SO_REUSEADDR) failed");
|
my_printfError("setsockopt(SO_REUSEPORT) failed");
|
||||||
addLog("set socket error", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
addLog("setsocketerror", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Bind socket
|
// Retry bind if it fails with EADDRINUSE
|
||||||
returnCode = bind(sock,(struct sockaddr*) &temp,sizeof(temp));
|
for (int i = 0; i < max_retries; i++)
|
||||||
|
{
|
||||||
|
returnCode = bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
|
||||||
|
if (returnCode == 0)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
printf("\n Success After: %d attempts", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (returnCode == -1)
|
if (errno == EADDRINUSE)
|
||||||
{
|
{
|
||||||
my_printf("\n Could not bind %d errno = %d", sock, errno);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sock != -1)
|
if (returnCode != 0)
|
||||||
{
|
{
|
||||||
close(sock);
|
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);
|
||||||
return returnCode;
|
close(sock);
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
//Number of client allowed
|
// Start listening
|
||||||
returnCode = listen(sock, 1);
|
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);
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (returnCode == -1)
|
return sock;
|
||||||
{
|
|
||||||
my_printf("\n Could not listen %d errno = %d", sock, errno);
|
|
||||||
if (sock != -1)
|
|
||||||
{
|
|
||||||
close(sock);
|
|
||||||
}
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user