summaryrefslogtreecommitdiff
path: root/src/ipcpd/ipcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipcpd/ipcp.c')
-rw-r--r--src/ipcpd/ipcp.c122
1 files changed, 83 insertions, 39 deletions
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
index 1c4fab94..87bf9e51 100644
--- a/src/ipcpd/ipcp.c
+++ b/src/ipcpd/ipcp.c
@@ -22,6 +22,7 @@
#include <ouroboros/config.h>
#include <ouroboros/ipcp.h>
+#include <ouroboros/time_utils.h>
#define OUROBOROS_PREFIX "ipcpd/ipcp"
#include <ouroboros/logs.h>
@@ -44,7 +45,8 @@ struct ipcp * ipcp_instance_create()
i->irmd_fd = -1;
i->state = IPCP_INIT;
- pthread_mutex_init(&i->state_lock, NULL);
+ pthread_rwlock_init(&i->state_lock, NULL);
+ pthread_mutex_init(&i->state_mtx, NULL);
pthread_condattr_init(&cattr);
pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
pthread_cond_init(&i->state_cond, &cattr);
@@ -52,14 +54,65 @@ struct ipcp * ipcp_instance_create()
return i;
}
-void ipcp_state_change(struct ipcp * ipcp,
- enum ipcp_state state)
+void ipcp_set_state(struct ipcp * ipcp,
+ enum ipcp_state state)
{
if (ipcp == NULL)
return;
+ pthread_mutex_lock(&ipcp->state_mtx);
+
ipcp->state = state;
+
pthread_cond_broadcast(&ipcp->state_cond);
+ pthread_mutex_unlock(&ipcp->state_mtx);
+}
+
+enum ipcp_state ipcp_get_state(struct ipcp * ipcp)
+{
+ enum ipcp_state state;
+
+ if (ipcp == NULL)
+ return IPCP_NULL;
+
+ pthread_mutex_lock(&ipcp->state_mtx);
+
+ state = ipcp->state;
+
+ pthread_mutex_unlock(&ipcp->state_mtx);
+
+ return state;
+}
+
+int ipcp_wait_state(struct ipcp * ipcp,
+ enum ipcp_state state,
+ const struct timespec * timeout)
+{
+ struct timespec abstime;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, timeout, &abstime);
+
+ pthread_mutex_lock(&ipcp->state_mtx);
+
+ while (ipcp->state != state && ipcp->state != IPCP_SHUTDOWN) {
+ int ret;
+ if (timeout == NULL)
+ ret = pthread_cond_wait(&ipcp->state_cond,
+ &ipcp->state_mtx);
+ else
+ ret = pthread_cond_timedwait(&ipcp->state_cond,
+ &ipcp->state_mtx,
+ &abstime);
+ if (ret) {
+ pthread_mutex_unlock(&ipcp->state_mtx);
+ return -ret;
+ }
+ }
+
+ pthread_mutex_unlock(&ipcp->state_mtx);
+
+ return 0;
}
int ipcp_parse_arg(int argc, char * argv[])
@@ -101,22 +154,6 @@ int ipcp_parse_arg(int argc, char * argv[])
return 0;
}
-static void close_ptr(void * o)
-{
- char * name = ipcp_sock_path(getpid());
- close(*((int *) o));
-
- if (unlink(name))
- LOG_DBG("Could not unlink %s.", name);
-
- free(name);
-}
-
-static void clean_msg(void * msg)
-{
- ipcp_msg__free_unpacked(msg, NULL);
-}
-
void * ipcp_main_loop(void * o)
{
int lsockfd;
@@ -135,9 +172,13 @@ void * ipcp_main_loop(void * o)
char * sock_path;
char * msg_name_dup;
- struct timeval tv = {(SOCKET_TIMEOUT / 1000),
+ struct timeval tv = {(IPCP_ACCEPT_TIMEOUT / 1000),
+ (IPCP_ACCEPT_TIMEOUT % 1000) * 1000};
+
+ struct timeval ltv = {(SOCKET_TIMEOUT / 1000),
(SOCKET_TIMEOUT % 1000) * 1000};
+
if (_ipcp == NULL) {
LOG_ERR("Invalid ipcp struct.");
return (void *) 1;
@@ -150,28 +191,33 @@ void * ipcp_main_loop(void * o)
sockfd = server_socket_open(sock_path);
if (sockfd < 0) {
LOG_ERR("Could not open server socket.");
+ free(sock_path);
return (void *) 1;
}
- free(sock_path);
-
- pthread_cleanup_push(close_ptr, (void *) &sockfd);
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
+ (void *) &tv, sizeof(tv)))
+ LOG_WARN("Failed to set timeout on socket.");
while (true) {
+ pthread_rwlock_rdlock(&_ipcp->state_lock);
+ if (ipcp_get_state(_ipcp) == IPCP_SHUTDOWN) {
+ pthread_rwlock_unlock(&_ipcp->state_lock);
+ break;
+ }
+
+ pthread_rwlock_unlock(&_ipcp->state_lock);
+
ret_msg.code = IPCP_MSG_CODE__IPCP_REPLY;
lsockfd = accept(sockfd, 0, 0);
- if (lsockfd < 0) {
- LOG_ERR("Cannot accept new connection");
- break;
- }
+ if (lsockfd < 0)
+ continue;
if (setsockopt(lsockfd, SOL_SOCKET, SO_RCVTIMEO,
- (void *) &tv, sizeof(tv)))
+ (void *) &ltv, sizeof(ltv)))
LOG_WARN("Failed to set timeout on socket.");
- pthread_cleanup_push(close_ptr, (void *) &lsockfd);
-
count = read(lsockfd, buf, IPCP_MSG_BUF_SIZE);
if (count <= 0) {
LOG_ERR("Failed to read from socket");
@@ -185,8 +231,6 @@ void * ipcp_main_loop(void * o)
continue;
}
- pthread_cleanup_push(clean_msg, (void *) msg);
-
switch (msg->code) {
case IPCP_MSG_CODE__IPCP_BOOTSTRAP:
if (_ipcp->ops->ipcp_bootstrap == NULL) {
@@ -201,7 +245,6 @@ void * ipcp_main_loop(void * o)
ret_msg.result = -1;
break;
}
-
if (conf_msg->ipcp_type == IPCP_NORMAL) {
conf.addr_size = conf_msg->addr_size;
conf.cep_id_size = conf_msg->cep_id_size;
@@ -218,7 +261,6 @@ void * ipcp_main_loop(void * o)
conf.ip_addr = conf_msg->ip_addr;
conf.dns_addr = conf_msg->dns_addr;
}
-
if (conf_msg->ipcp_type == IPCP_SHIM_ETH_LLC)
conf.if_name = conf_msg->if_name;
@@ -295,8 +337,7 @@ void * ipcp_main_loop(void * o)
break;
}
- pthread_cleanup_pop(true);
- pthread_cleanup_pop(false);
+ ipcp_msg__free_unpacked(msg, NULL);
buffer.len = ipcp_msg__get_packed_size(&ret_msg);
if (buffer.len == 0) {
@@ -321,10 +362,13 @@ void * ipcp_main_loop(void * o)
free(buffer.data);
close(lsockfd);
-
}
- pthread_cleanup_pop(true);
+ close(sockfd);
+ if (unlink(sock_path))
+ LOG_DBG("Could not unlink %s.", sock_path);
+
+ free(sock_path);
- return NULL;
+ return (void *) 0;
}