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