summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordaniel <danieruru@gmail.com>2013-01-26 13:10:08 +0900
committerdaniel <danieruru@gmail.com>2013-01-26 13:10:08 +0900
commit35b28230e17a68db48f3b5fc91d2eec0c80e048c (patch)
tree3682265dbce6a376a9f65835d718515f448a4972
parent67801485ab5a9e4509d2bb2cdd9454ee4ed1ab11 (diff)
Add a "hack" to report back to the vxi11 service code when a link dies.
It's a hack because linux/glibc's RPC implementation doesn't seem to have the ability to set a recv error callback. The hack is to add an extra event to the events poll'd.. that event tells us if the socket died.
-rw-r--r--libvxi11client/libvxi11client.c6
-rw-r--r--vxi11_server.c39
-rw-r--r--vxi11_server.h1
-rw-r--r--vxi11_svc.c55
4 files changed, 87 insertions, 14 deletions
diff --git a/libvxi11client/libvxi11client.c b/libvxi11client/libvxi11client.c
index 743168f..0e01809 100644
--- a/libvxi11client/libvxi11client.c
+++ b/libvxi11client/libvxi11client.c
@@ -214,8 +214,10 @@ int vxi11_read(VXI11Context* context, char* buffer, unsigned int bufferlen, bool
#ifdef DEBUG
printf("Got \"%s\" from server\n", resp->data.data_val);
#endif
- if (buffer != NULL)
- strncpy(buffer, resp->data.data_val, (bufferlen < resp->data.data_len ? bufferlen : resp->data.data_len));
+ if (buffer != NULL && resp->data.data_val != NULL) {
+ int lengthtocopy = ((bufferlen - 1) < resp->data.data_len ? (bufferlen - 1) : resp->data.data_len);
+ strncpy(buffer, resp->data.data_val, lengthtocopy);
+ }
#ifdef DEBUG
else
printf("Supplied buffer is null!\n");
diff --git a/vxi11_server.c b/vxi11_server.c
index ae8317f..4185542 100644
--- a/vxi11_server.c
+++ b/vxi11_server.c
@@ -47,6 +47,7 @@ static gchar* inthandler = NULL;
#define LINKLONGSINCEDEADTIMEOUT ((10 * 60) * 1000000) // ten minutes
typedef struct {
int lid;
+ int sock;
GTimeVal lastactivity;
} ActiveLink;
@@ -66,6 +67,29 @@ static bool isValidLink(int linkid) {
return links[linkid] != NULL;
}
+static void freelink(ActiveLink* link) {
+ links[link->lid] = NULL;
+ globals.Remote.vxi_connections--;
+#ifdef DEBUG
+ printf("link %d destroyed, %d active links\n", link->lid, globals.Remote.vxi_connections);
+#endif
+ g_free(link);
+}
+
+void vxi11_deadsocketcallback(int socket) {
+ int linkid;
+ for (linkid = 0; linkid < SIZEOFARRAY(links); linkid++) {
+ if (links[linkid] != NULL) {
+ if (links[linkid]->sock == socket) {
+#ifdef DEBUG
+ printf("Freeing link %d, socket died\n", linkid);
+#endif
+ freelink(links[linkid]);
+ }
+ }
+ }
+}
+
// test if a link has expired, this is to avoid dead locks
static bool linkexpired(ActiveLink* link) {
GTimeVal cutoff;
@@ -75,9 +99,7 @@ static bool linkexpired(ActiveLink* link) {
#ifdef DEBUG
printf("Link %d is apparently dead, removing\n", link->lid);
#endif
- links[link->lid] = NULL;
- g_free(link);
- globals.Remote.vxi_connections--;
+ freelink(link);
return true;
}
else
@@ -171,10 +193,11 @@ create_link_1_svc(Create_LinkParms *argp, struct svc_req *rqstp) {
}
g_assert(linkid != SIZEOFARRAY(links));
link->lid = linkid;
+ link->sock = rqstp->rq_xprt->xp_sock;
touchlink(linkid);
globals.Remote.vxi_connections++;
#ifdef DEBUG
- printf("created link %d, %d active links\n", linkid, globals.Remote.vxi_connections);
+ printf("created link %d(socket %d), %d active links\n", linkid, link->sock, globals.Remote.vxi_connections);
#endif
struct sockaddr_in sin;
@@ -184,6 +207,7 @@ create_link_1_svc(Create_LinkParms *argp, struct svc_req *rqstp) {
result.abortPort = ntohs(sin.sin_port);
result.maxRecvSize = MAXRECV;
result.lid = linkid;
+
}
}
return &result;
@@ -468,13 +492,8 @@ destroy_link_1_svc(Device_Link *argp, struct svc_req *rqstp) {
unlock();
}
- globals.Remote.vxi_connections--;
-#ifdef DEBUG
- printf("link %d destroyed, %d active links\n", lid, globals.Remote.vxi_connections);
-#endif
+ freelink(links[lid]);
result.error = 0;
- g_free(links[lid]);
- links[lid] = NULL;
}
return &result;
diff --git a/vxi11_server.h b/vxi11_server.h
index f682f58..5c4450d 100644
--- a/vxi11_server.h
+++ b/vxi11_server.h
@@ -1 +1,2 @@
void vxi11_fireinterrupt(void);
+void vxi11_deadsocketcallback(int socket);
diff --git a/vxi11_svc.c b/vxi11_svc.c
index edc4212..e5c4b38 100644
--- a/vxi11_svc.c
+++ b/vxi11_svc.c
@@ -1,12 +1,18 @@
+#define _GNU_SOURCE
+
#include "vxi11.h"
+#include "vxi11_server.h"
#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
+#include <poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#define VXI11_DEFAULT_TIMEOUT 1000
+
#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif
@@ -223,6 +229,51 @@ void vxi_main() {
exit(1);
}
- svc_run();
- fprintf(stderr, "%s", "svc_run returned");
+ int i, j;
+ struct pollfd *my_pollfd = NULL;
+ int last_max_pollfd = 0;
+
+ while (1) {
+ int max_pollfd = svc_max_pollfd;
+ if (max_pollfd == 0 && svc_pollfd == NULL)
+ break;
+
+ if (last_max_pollfd != max_pollfd) {
+ struct pollfd *new_pollfd = realloc(my_pollfd, sizeof(struct pollfd) * max_pollfd);
+
+ if (new_pollfd == NULL) {
+ break;
+ }
+
+ my_pollfd = new_pollfd;
+ last_max_pollfd = max_pollfd;
+ }
+
+ for (i = 0; i < max_pollfd; ++i) {
+ my_pollfd[i].fd = svc_pollfd[i].fd;
+ my_pollfd[i].events = svc_pollfd[i].events | POLLRDHUP; // add the "socket is dead" event
+ my_pollfd[i].revents = 0;
+ }
+
+ j = poll(my_pollfd, max_pollfd, VXI11_DEFAULT_TIMEOUT);
+
+ for (i = 0; i < max_pollfd; i++) {
+ if (my_pollfd[i].revents & POLLRDHUP)
+ vxi11_deadsocketcallback(my_pollfd[i].fd);
+ }
+
+ switch (j) {
+ case -1:
+ break;
+ case 0:
+ continue;
+ default:
+ svc_getreq_poll(my_pollfd, i);
+ continue;
+ }
+ break;
+ }
+
+ //svc_run();
+ //fprintf(stderr, "%s", "svc_run returned");
}