]> git.lizzy.rs Git - dragonnet.git/blob - peer.c
Refactor type hooks
[dragonnet.git] / peer.c
1 #include <assert.h>
2 #include <dragonnet/peer.h>
3 #include <dragonnet/recv.h>
4 #include <dragonnet/recv_thread.h>
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 static bool dragonnet_peer_init(DragonnetPeer *p, char *addr)
10 {
11         pthread_rwlock_init(&p->mu, NULL);
12         pthread_rwlock_wrlock(&p->mu);
13
14         p->sock = socket(AF_INET6, SOCK_STREAM, 0);
15         p->raddr = dragonnet_addr_parse_str(addr);
16         p->on_recv_type = calloc(sizeof *p->on_recv_type, dragonnet_num_types);
17
18         struct sockaddr_in6 sock_addr = dragonnet_addr_sock(p->raddr);
19         if (connect(p->sock, (const struct sockaddr *) &sock_addr,
20                         sizeof sock_addr) < 0) {
21                 perror("connect");
22                 return false;
23         }
24
25         struct sockaddr_in6 sock_name;
26         socklen_t sock_namelen = sizeof sock_name;
27
28         if (getsockname(p->sock, (struct sockaddr *) &sock_name, &sock_namelen) < 0) {
29                 perror("getsockname");
30                 return false;
31         }
32
33         p->laddr = dragonnet_addr_parse_sock(sock_name);
34
35         pthread_rwlock_unlock(&p->mu);
36         return true;
37 }
38
39 DragonnetPeer *dragonnet_connect(char *addr)
40 {
41         DragonnetPeer *p = malloc(sizeof *p);
42         if (!dragonnet_peer_init(p, addr)) {
43                 dragonnet_peer_delete(p);
44                 return NULL;
45         }
46
47         return p;
48 }
49
50 void dragonnet_peer_set_recv_hook(DragonnetPeer *p, u16 type_id,
51                 void (*on_recv)(struct dragonnet_peer *, void *))
52 {
53         pthread_rwlock_rdlock(&p->mu);
54         DragonnetPeerState state = p->state;
55         pthread_rwlock_unlock(&p->mu);
56
57         if (state >= DRAGONNET_PEER_ACTIVE)
58                 return;
59
60         pthread_rwlock_wrlock(&p->mu);
61         p->on_recv_type[type_id] = on_recv;
62         pthread_rwlock_unlock(&p->mu);
63 }
64
65 void dragonnet_peer_run(DragonnetPeer *p)
66 {
67         pthread_rwlock_wrlock(&p->mu);
68         pthread_create(&p->recv_thread, NULL, &dragonnet_peer_recv_thread, p);
69         pthread_rwlock_unlock(&p->mu);
70
71         while (p->state < DRAGONNET_PEER_ACTIVE);
72 }
73
74 void dragonnet_peer_close(DragonnetPeer *p)
75 {
76         pthread_rwlock_wrlock(&p->mu);
77
78         pthread_t recv_thread = p->recv_thread;
79         if (p->state == DRAGONNET_PEER_ACTIVE)
80                 shutdown(p->sock, SHUT_RDWR);
81
82         pthread_rwlock_unlock(&p->mu);
83
84         pthread_cancel(recv_thread);
85         pthread_join(recv_thread, NULL);
86 }
87
88 void dragonnet_peer_delete(DragonnetPeer *p)
89 {
90         pthread_rwlock_destroy(&p->mu);
91         free(p);
92 }