Fix networking bugs
[mspang/pyceo.git] / src / net.c
1 #include <stdio.h>
2 #include <sys/utsname.h>
3 #include <unistd.h>
4 #include <netdb.h>
5 #include <errno.h>
6
7 #include "util.h"
8 #include "net.h"
9 #include "gss.h"
10 #include "strbuf.h"
11
12 struct strbuf fqdn = STRBUF_INIT;
13
14 const size_t MAX_MSGLEN = 65536;
15 const size_t MSG_BUFINC = 4096;
16
17 void setup_fqdn(void) {
18     struct utsname uts;
19     struct hostent *lo;
20
21     if (uname(&uts))
22         fatalpe("uname");
23     lo = gethostbyname(uts.nodename);
24     if (!lo)
25         fatalpe("gethostbyname");
26
27     strbuf_addstr(&fqdn, lo->h_name);
28 }
29
30 void free_fqdn(void) {
31     strbuf_release(&fqdn);
32 }
33
34 static size_t recv_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg, int *notification) {
35     size_t len = 0;
36     int flags = 0;
37     int bytes;
38
39     strbuf_reset(msg);
40
41     do {
42         msg_meta->fromlen = sizeof(msg_meta->from);
43
44         bytes = sctp_recvmsg(sock, msg->buf + len, strbuf_avail(msg) - len,
45                              (sa *)&msg_meta->from, &msg_meta->fromlen, &msg_meta->sinfo, &flags);
46
47         if (bytes < 0) {
48             if (errno == EAGAIN)
49                 continue;
50             fatalpe("sctp_recvmsg");
51         }
52         if (!bytes)
53             break;
54         len += bytes;
55
56         if (msg->len > MAX_MSGLEN)
57             fatal("oversized message received");
58         if (strbuf_avail(msg) < MSG_BUFINC)
59             strbuf_grow(msg, MSG_BUFINC);
60
61     } while (~flags & MSG_EOR);
62
63     if (!bytes && len)
64         fatalpe("EOF in the middle of a message");
65
66     *notification = flags & MSG_NOTIFICATION;
67     if (*notification) {
68         notification_dbg(msg->buf);
69         union sctp_notification *sn = (union sctp_notification *) msg->buf;
70         switch (sn->sn_header.sn_type) {
71             case SCTP_SHUTDOWN_EVENT:
72                 fatal("connection shut down");
73                 break;
74         }
75     }
76
77     strbuf_setlen(msg, len);
78     return len;
79 }
80
81 int receive_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg) {
82     int notification = 0;
83
84     do {
85         recv_one_message(sock, msg_meta, msg, &notification);
86     } while (notification);
87
88     return msg->len > 0;
89 }
90
91 void notification_dbg(char *notification) {
92     union sctp_notification *sn = (union sctp_notification *) notification;
93     char *extra;
94
95     switch (sn->sn_header.sn_type) {
96         case SCTP_ASSOC_CHANGE:
97             extra = "unknown state";
98             switch (sn->sn_assoc_change.sac_state) {
99                 case SCTP_COMM_UP: extra = "established"; break;
100                 case SCTP_COMM_LOST: extra = "lost"; break;
101                 case SCTP_RESTART: extra = "restarted"; break;
102                 case SCTP_SHUTDOWN_COMP: extra = "completed shutdown"; break;
103                 case SCTP_CANT_STR_ASSOC: extra = "cannot start"; break;
104             }
105             debug("association changed: association 0x%x %s", sn->sn_assoc_change.sac_assoc_id, extra);
106             break;
107         case SCTP_PEER_ADDR_CHANGE:
108             extra = "unknown state";
109             switch (sn->sn_paddr_change.spc_state) {
110                 case SCTP_ADDR_AVAILABLE: extra = "unavailable"; break;
111                 case SCTP_ADDR_UNREACHABLE: extra = "unreachable"; break;
112                 case SCTP_ADDR_REMOVED: extra = "removed"; break;
113                 case SCTP_ADDR_ADDED: extra = "added"; break;
114                 case SCTP_ADDR_MADE_PRIM: extra = "made primary"; break;
115 #ifdef SCTP_ADDR_CONFIRMED
116                 case SCTP_ADDR_CONFIRMED: extra = "confirmed"; break;
117 #endif
118             }
119
120             struct sockaddr_in *sa = (struct sockaddr_in *) &sn->sn_paddr_change.spc_aaddr;
121             char addr[INET_ADDRSTRLEN];
122             inet_ntop(AF_INET, &sa->sin_addr, addr, sizeof(addr));
123             debug("peer address change: remote address %s %s", addr, extra);
124             break;
125         case SCTP_REMOTE_ERROR:
126             debug("remote error: association=0x%x error=0x%x",
127                     sn->sn_remote_error.sre_assoc_id,
128                     sn->sn_remote_error.sre_error);
129             break;
130         case SCTP_SEND_FAILED:
131             debug("send failed: association=0x%x error=0x%x",
132                     sn->sn_send_failed.ssf_assoc_id,
133                     sn->sn_send_failed.ssf_error);
134             break;
135         case SCTP_ADAPTATION_INDICATION:
136             debug("adaptation indication: 0x%x",
137                     sn->sn_adaptation_event.sai_adaptation_ind);
138             break;
139         case SCTP_PARTIAL_DELIVERY_EVENT:
140             extra = "unknown indication";
141             switch (sn->sn_pdapi_event.pdapi_indication) {
142                 case SCTP_PARTIAL_DELIVERY_ABORTED:
143                     extra = "partial delivery aborted";
144                     break;
145             }
146             debug("partial delivery event: %s", extra);
147             break;
148         case SCTP_SHUTDOWN_EVENT:
149             debug("association 0x%x was shut down",
150                     sn->sn_shutdown_event.sse_assoc_id);
151             break;
152         default:
153             debug("unknown sctp notification type 0x%x\n",
154                     sn->sn_header.sn_type);
155     }
156 }