[client] added ivshmem client tracking and removal

This commit is contained in:
Geoffrey McRae 2017-10-19 17:54:00 +11:00
parent aaa18e595e
commit 327a3a77cf
2 changed files with 163 additions and 4 deletions

View File

@ -4,6 +4,7 @@
#define DEBUG_IVSHMEM #define DEBUG_IVSHMEM
#include "debug.h" #include "debug.h"
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
@ -15,21 +16,38 @@
#include <sys/mman.h> #include <sys/mman.h>
#define MAX_IRQS 32
struct IVSHMEMServer struct IVSHMEMServer
{ {
int64_t version; int64_t version;
int64_t clientID; int64_t clientID;
int sharedFD; int sharedFD;
int irqs[MAX_IRQS];
int irqCount;
};
struct IVSHMEMClient
{
uint16_t clientID;
int irqs[MAX_IRQS];
int irqCount;
struct IVSHMEMClient * last;
struct IVSHMEMClient * next;
}; };
struct IVSHMEM struct IVSHMEM
{ {
bool connected; bool connected;
int socket; int socket;
struct IVSHMEMServer server; struct IVSHMEMServer server;
struct IVSHMEMClient * clients;
off_t mapSize; off_t mapSize;
void * map; void * map;
}; };
struct IVSHMEM ivshmem = struct IVSHMEM ivshmem =
@ -44,6 +62,8 @@ struct IVSHMEM ivshmem =
void ivshmem_cleanup(); void ivshmem_cleanup();
bool ivshmem_read(void * buffer, const ssize_t size); bool ivshmem_read(void * buffer, const ssize_t size);
bool ivshmem_read_msg(int64_t * index, int *fd); bool ivshmem_read_msg(int64_t * index, int *fd);
struct IVSHMEMClient * ivshmem_get_client(uint16_t clientID);
void ivshmem_remove_client(struct IVSHMEMClient * client);
// ============================================================================ // ============================================================================
@ -133,6 +153,23 @@ bool ivshmem_connect(const char * unix_socket)
void ivshmem_cleanup() void ivshmem_cleanup()
{ {
struct IVSHMEMClient * client, * next;
client = ivshmem.clients;
while(client)
{
for(int i = 0; i < client->irqCount; ++i)
close(client->irqs[i]);
next = client->next;
free(client);
client = next;
}
ivshmem.clients = NULL;
for(int i = 0; i < ivshmem.server.irqCount; ++i)
close(ivshmem.server.irqs[i]);
ivshmem.server.irqCount = 0;
if (ivshmem.map) if (ivshmem.map)
munmap(ivshmem.map, ivshmem.mapSize); munmap(ivshmem.map, ivshmem.mapSize);
ivshmem.map = NULL; ivshmem.map = NULL;
@ -278,4 +315,125 @@ size_t ivshmem_get_map_size()
} }
return ivshmem.mapSize; return ivshmem.mapSize;
}
// ============================================================================
struct IVSHMEMClient * ivshmem_get_client(uint16_t clientID)
{
struct IVSHMEMClient * client = NULL;
if (ivshmem.clients == NULL)
{
client = (struct IVSHMEMClient *)malloc(sizeof(struct IVSHMEMClient));
client->clientID = clientID;
client->last = NULL;
client->next = NULL;
client->irqCount = 0;
ivshmem.clients = client;
return client;
}
client = ivshmem.clients;
while(client)
{
if (client->clientID == clientID)
return client;
client = client->next;
}
client = (struct IVSHMEMClient *)malloc(sizeof(struct IVSHMEMClient));
client->clientID = clientID;
client->last = NULL;
client->next = ivshmem.clients;
client->irqCount = 0;
client->next->last = client;
ivshmem.clients = client;
return client;
}
// ============================================================================
void ivshmem_remove_client(struct IVSHMEMClient * client)
{
if (client->last)
client->last->next = client->next;
if (client->next)
client->next->last = client->last;
if (ivshmem.clients == client)
ivshmem.clients = client->next;
free(client);
}
// ============================================================================
bool ivshmem_process()
{
int64_t index;
int fd;
if (!ivshmem_read_msg(&index, &fd))
{
DEBUG_ERROR("failed to read message");
return false;
}
if (index == -1)
{
DEBUG_ERROR("invalid index -1");
return false;
}
if (index > 0xFFFF)
{
DEBUG_ERROR("invalid index > 0xFFFF");
return false;
}
if (index == ivshmem.server.clientID)
{
if (fd == -1)
{
DEBUG_ERROR("server sent disconnect");
return false;
}
if (ivshmem.server.irqCount == MAX_IRQS)
{
DEBUG_WARN("maximum IRQs reached, closing extra");
close(fd);
return true;
}
ivshmem.server.irqs[ivshmem.server.irqCount++] = fd;
return true;
}
struct IVSHMEMClient * client = ivshmem_get_client(index);
if (!client)
{
DEBUG_ERROR("failed to get/create client record");
return false;
}
if (fd == -1)
{
DEBUG_PROTO("remove client %u", client->clientID);
ivshmem_remove_client(client);
return true;
}
if (client->irqCount == MAX_IRQS)
{
DEBUG_WARN("maximum client IRQs reached, closing extra");
close(fd);
return true;
}
client->irqs[client->irqCount++] = fd;
return true;
} }

View File

@ -4,6 +4,7 @@
bool ivshmem_connect(const char * unix_socket); bool ivshmem_connect(const char * unix_socket);
void ivshmem_close(); void ivshmem_close();
bool ivshmem_process();
void * ivshmem_get_map(); void * ivshmem_get_map();
size_t ivshmem_get_map_size(); size_t ivshmem_get_map_size();