fix a header guard
[libof.git] / libof.c
blob66cb5ec435d9fabb34e1883c2e3fc33859ef8dde
1 /*
2 * Copyright (c) 2015 Mohamed Aslan <maslan@sce.carleton.ca>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <err.h>
23 #include <time.h>
24 #include <assert.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <sys/event.h>
28 #include <netinet/in.h>
30 #include "libof.h"
31 #include "hashtab.h"
33 #define MAXTIMERS 100
34 #define TCPBACKLOG 500
35 #define HEARTBEAT 5
38 #ifdef DEBUG
39 static void
40 of_print_header(struct ofp_header *hdr)
42 if (hdr == NULL)
43 return;
44 printf("header -> {version = %d, type = %d, length = %d, xid = %x}\n",
45 (unsigned int)hdr->version,
46 (unsigned int)hdr->type,
47 (unsigned int)be16toh(hdr->length),
48 (unsigned int)be32toh(hdr->xid));
50 #endif
52 static void
53 sendtosocket(int skt, struct ofp_header *hdr)
55 assert(be16toh(hdr->length) >= sizeof(struct ofp_header));
56 if (be16toh(hdr->length) >= sizeof(struct ofp_header))
57 write(skt, hdr, (size_t)be16toh(hdr->length)); // FIXME: error check
60 static void
61 send_msg(struct of_controller *controller, struct of_dataplane *dp, struct ofp_header *hdr)
63 if (controller == NULL || dp == NULL || hdr == NULL)
64 return;
65 sendtosocket(dp->socket, hdr);
68 static void
69 heartbeat(struct of_controller *controller)
71 size_t iter, ksz, vsz;
72 time_t now;
73 uintptr_t *ptr;
74 uint64_t *dpid;
75 struct of_dataplane *dp;
77 now = time(NULL);
78 /* TODO: something smarter */
79 HASHTAB_FOREACH(controller->dpids, iter, dpid, ksz, ptr, vsz) {
80 hashtab_at(&(controller->dpids), iter, (void **)(&dpid), &ksz, (void **)(&ptr), &vsz);
81 dp = (struct of_dataplane *)(*ptr);
82 if (dp->ready && (now >= (dp->lastmsg_ts + HEARTBEAT))) {
83 #ifdef DEBUG
84 printf("last pinged %ju, now is %ju (%ju)\n", dp->lastmsg_ts, now, (now - dp->lastmsg_ts));
85 printf("heartbeating: dpid 0x%llx\n", *dpid);
86 #endif
87 dp->protocol->ping(controller, dp);
92 static void
93 timer(struct of_controller *controller, unsigned int period, void (*callback)(struct of_controller *))
95 int tid;
96 struct kevent kev;
97 uintptr_t ptr;
99 if (controller->n_timers >= MAXTIMERS)
100 return;
101 tid = controller->n_timers;
102 ptr = (uintptr_t)callback;
103 EV_SET(&kev, tid, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, period, NULL);
104 if ((kevent(controller->ev_queue, &kev, 1, NULL, 0, NULL)) == -1)
105 errx(1, "timer");
106 /*printf("callback: 0x%llx (%zu)\n", ptr, sizeof(uintptr_t));*/
107 if (!hashtab_put(&(controller->timer_callbacks), (void *)(&tid), sizeof(int), (void *)(&ptr), sizeof(uintptr_t)))
108 errx(1, "hashtab_put");
109 controller->n_timers++;
112 static void
113 handler(struct of_controller *controller, void (*callback)(struct of_controller *, struct of_event *))
115 controller->of_handler = callback;
118 static void
119 event_loop(struct of_controller *controller)
121 char buf[BUFSIZ + 1];
122 size_t sz;
123 ssize_t bytes;
124 int n, s;
125 struct kevent kev;
126 struct sockaddr_in sa;
127 struct sockaddr_storage sw_addr;
128 struct of_dataplane *dp;
129 struct ofp_header *recv;
130 socklen_t addr_len = sizeof(struct sockaddr_storage);
131 uintptr_t p, *ptr;
132 void (*callback)(struct of_controller *);
134 if (controller == NULL)
135 return;
136 if ((controller->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
137 return;
138 memset(&sa, 0, sizeof sa);
139 sa.sin_family = AF_INET;
140 sa.sin_port = htons(controller->port);
141 sa.sin_addr.s_addr = htonl(INADDR_ANY);
143 if (bind(controller->socket, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
144 close(controller->socket);
145 return;
148 if (listen(controller->socket, TCPBACKLOG) == -1) {
149 close(controller->socket);
150 return;
153 EV_SET(&kev, controller->socket, EVFILT_READ, EV_ADD, 0, 0, NULL);
154 if ((kevent(controller->ev_queue, &kev, 1, NULL, 0, NULL)) == -1) {
155 close(controller->socket);
156 return;
159 while(1) {
160 n = kevent(controller->ev_queue, NULL, 0, &kev, 1, NULL); /* TODO: use bigger eventlist */
161 if (n == -1)
162 errx(1, "event_loop");
163 else if (n == 0)
164 continue;
165 if (kev.filter == EVFILT_TIMER) { /* timers */
166 s = (int)(kev.ident); /* uintptr_t != int */
167 if (!hashtab_get(&(controller->timer_callbacks), (void *)(&s), sizeof(int), (void **)(&ptr), &sz))
168 errx(1, "hashtab_get");
169 callback = (void (*)(struct of_controller *))(*ptr);
170 //printf("callback: 0x%llx (%zu) for timer %d\n", callback, sz, s);
171 callback(controller);
172 } else if (kev.filter == EVFILT_READ) { /* sockets */
173 s = (int)(kev.ident); /* uintptr_t != int */
174 if (s == controller->socket) { /* server socket: new connection */
175 dp = (struct of_dataplane *)calloc(1, sizeof(struct of_dataplane));
176 dp->socket = accept(controller->socket, (struct sockaddr *)&sw_addr, &addr_len);
177 if (fcntl(dp->socket, F_SETFL, O_NONBLOCK) == -1)
178 errx(1, "fcntl");
179 p = (uintptr_t)dp;
180 if (!hashtab_put(&(controller->conns), (void *)(&(dp->socket)), sizeof(dp->socket), (void *)(&p), sizeof(uintptr_t)))
181 errx(1, "hashtab_put");
182 printf("new connection.\n");
183 EV_SET(&kev, dp->socket, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, NULL);
184 if ((kevent(controller->ev_queue, &kev, 1, NULL, 0, NULL)) == -1) {
185 close(dp->socket);
186 return;
188 controller->protocol->handshake(controller, dp);
189 } else { /* a client socket */
190 bytes = read(s, buf, sizeof(buf));
191 if (bytes == 0) {
192 printf("connection closed.\n");
193 EV_SET(&kev, s, EVFILT_READ, EV_DELETE, 0, 0, NULL);
194 if ((kevent(controller->ev_queue, &kev, 1, NULL, 0, NULL)) == -1) {
195 close(s);
196 return;
198 close(s);
199 /* TODO: remove from hashtabs and free structs */
201 else if (bytes < sizeof(struct ofp_header)) {
202 printf("error! %zd\n", bytes);
203 return;
205 else {
206 if (!hashtab_get(&(controller->conns), (void *)&s, sizeof(s), (void **)(&ptr), &sz))
207 errx(1, "hashtab_get");
208 assert(sz == sizeof(uintptr_t));
209 dp = (struct of_dataplane *)(*ptr);
210 #ifdef DEBUG
211 printf("read %zd bytes.\n", bytes);
212 #endif
213 recv = (struct ofp_header *)buf;
214 dp->lastmsg_ts = time(NULL);
215 controller->protocol->recv(controller, dp, recv);
223 of_controller_init(struct of_controller *controller, int port, const struct of_protocol *proto)
225 if ((controller->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
226 return 1;
227 controller->port = port;
228 controller->n_timers = 0;
229 controller->protocol = proto;
230 controller->send = send_msg;
231 controller->loop = event_loop;
232 controller->timer = timer;
233 controller->handler = handler;
234 controller->of_handler = NULL;
235 if ((controller->ev_queue = kqueue()) == -1)
236 errx(1, "kqueue");
237 if (!hashtab_init(&(controller->conns), 8, NULL))
238 errx(1, "hashtab_init");
239 if (!hashtab_init(&(controller->dpids), 8, NULL))
240 errx(1, "hashtab_init");
241 if (!hashtab_init(&(controller->timer_callbacks), 8, NULL))
242 errx(1, "hashtab_init");
243 controller->timer(controller, 3000, heartbeat);
244 return 0;