9653f9465cd38083798352930ab6e8553b5a96cf
[olsrd.git] / lib / quagga / src / client.c
1 /*
2  * OLSRd Quagga plugin
3  *
4  * Copyright (C) 2006-2008 Immo 'FaUl' Wehrenberg <immo@chaostreff-dortmund.de>
5  * Copyright (C) 2007-2012 Vasilis Tsiligiannis <acinonyxs@yahoo.gr>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation or - at your option - under
10  * the terms of the GNU General Public Licence version 2 but can be
11  * linked to any BSD-Licenced Software with public available sourcecode
12  *
13  */
14
15 /* -------------------------------------------------------------------------
16  * File               : client.c
17  * Description        : zebra client functions
18  * ------------------------------------------------------------------------- */
19
20 #define HAVE_SOCKLEN_T
21
22 #include <sys/un.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include "defs.h"
26 #include "olsr.h"
27 #include "log.h"
28 #include "routing_table.h"
29
30 #include "common.h"
31 #include "quagga.h"
32 #include "packet.h"
33 #include "client.h"
34
35 static void *my_realloc(void *, size_t, const char *);
36 static void zclient_connect(void);
37
38 static void *
39 my_realloc(void *buf, size_t s, const char *c)
40 {
41
42   buf = realloc(buf, s);
43   if (!buf) {
44     OLSR_PRINTF(1, "(QUAGGA) Out of memory: %s!\n", strerror(errno));
45     olsr_syslog(OLSR_LOG_ERR, "(QUAGGA) Out of memory!\n");
46     olsr_exit(c, EXIT_FAILURE);
47   }
48
49   return buf;
50 }
51
52 static void
53 zclient_connect(void)
54 {
55   int ret;
56
57   union {
58     struct sockaddr_in sin;
59     struct sockaddr_un sun;
60   } sockaddr;
61
62   if (close(zebra.sock) < 0)
63     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
64   zebra.sock = socket(zebra.port ? AF_INET : AF_UNIX, SOCK_STREAM, 0);
65
66   if (zebra.sock < 0)
67     olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE);
68
69   memset(&sockaddr, 0, sizeof sockaddr);
70
71   if (zebra.port) {
72     sockaddr.sin.sin_family = AF_INET;
73     sockaddr.sin.sin_port = htons(zebra.port);
74     sockaddr.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
75     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sin, sizeof sockaddr.sin);
76   } else {
77     sockaddr.sun.sun_family = AF_UNIX;
78     strscpy(sockaddr.sun.sun_path, zebra.sockpath, sizeof(sockaddr.sun.sun_path));
79     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sun, sizeof sockaddr.sun);
80   }
81
82   if (ret < 0)
83     zebra.status &= ~STATUS_CONNECTED;
84   else
85     zebra.status |= STATUS_CONNECTED;
86
87 }
88
89 void
90 zclient_reconnect(void)
91 {
92   struct rt_entry *tmp;
93
94   zclient_connect();
95   if (!(zebra.status & STATUS_CONNECTED))
96     return;                     // try again next time
97
98   zebra_hello(ZEBRA_HELLO);
99   if (zebra.options & OPTION_EXPORT) {
100     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
101       zebra_addroute(tmp);
102     }
103     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
104   }
105   zebra_redistribute(ZEBRA_REDISTRIBUTE_ADD);
106
107 }
108
109 int
110 zclient_write(unsigned char *options)
111 {
112   unsigned char *pnt;
113   uint16_t len;
114   int ret;
115
116   if (!(zebra.status & STATUS_CONNECTED))
117     return 0;
118
119   pnt = options;
120   memcpy(&len, pnt, sizeof len);
121
122   len = ntohs(len);
123
124   do {
125     ret = write(zebra.sock, pnt, len);
126     if (ret < 0) {
127       if ((errno == EINTR) || (errno == EAGAIN)) {
128         errno = 0;
129         ret = 0;
130         continue;
131       } else {
132         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra.\n");
133         zebra.status &= ~STATUS_CONNECTED;
134         /* TODO: Remove HNAs added from redistribution */
135         free(options);
136         return -1;
137       }
138     }
139     pnt = pnt + ret;
140   }
141   while ((len -= ret));
142   free(options);
143
144   return 0;
145 }
146
147 unsigned char *
148 zclient_read(ssize_t * size)
149 {
150   unsigned char *buf;
151   ssize_t bytes, bufsize;
152   uint16_t length, offset;
153   int sockstatus;
154
155   /* initialize variables */
156   buf = NULL;
157   offset = 0;
158   *size = 0;
159   bufsize = 0;
160
161   /* save socket status and set non-blocking for read */
162   sockstatus = fcntl(zebra.sock, F_GETFL);
163   (void)fcntl(zebra.sock, F_SETFL, sockstatus|O_NONBLOCK);
164
165   /* read whole packages */
166   do {
167
168     /* (re)allocate buffer */
169     if (*size == bufsize) {
170       bufsize += BUFSIZE;
171       buf = my_realloc(buf, bufsize, "QUAGGA: Grow read buffer");
172     }
173
174     /* read from socket */
175     bytes = read(zebra.sock, buf + *size, bufsize - *size);
176     /* handle broken packet */
177     if (!bytes) {
178       free(buf);
179       return NULL;
180     }
181     /* handle no data available */
182     if (bytes < 0) {
183       /* handle disconnect */
184       if (errno != EAGAIN) {    // oops - we got disconnected
185         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
186         zebra.status &= ~STATUS_CONNECTED;
187         /* TODO: Remove HNAs added from redistribution */
188       }
189       free(buf);
190       return NULL;
191     }
192
193     *size += bytes;
194
195     /* detect zebra packet fragmentation */
196     do {
197       memcpy(&length, buf + offset, sizeof length);
198       length = ntohs(length);
199       offset += length;
200     }
201     while (*size >= (ssize_t) (offset + sizeof length));
202     /* set blocking socket on fragmented packet */
203     if (*size != offset)
204       (void)fcntl(zebra.sock, F_SETFL, sockstatus);
205
206   }
207   while (*size != offset);
208
209   /* restore socket status */
210   (void)fcntl(zebra.sock, F_SETFL, sockstatus);
211
212   return buf;
213 }
214
215 /*
216  * Local Variables:
217  * c-basic-offset: 2
218  * indent-tabs-mode: nil
219  * End:
220  */