quagga: use the new olsr_realloc function
[olsrd.git] / lib / quagga / src / client.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 /* -------------------------------------------------------------------------
47  * File               : client.c
48  * Description        : zebra client functions
49  * ------------------------------------------------------------------------- */
50
51 #define HAVE_SOCKLEN_T
52
53 #include <sys/un.h>
54 #include <unistd.h>
55 #include <fcntl.h>
56 #include "defs.h"
57 #include "olsr.h"
58 #include "log.h"
59 #include "routing_table.h"
60 #include "common/autobuf.h"
61
62 #include "common.h"
63 #include "quagga.h"
64 #include "packet.h"
65 #include "client.h"
66
67 static void zclient_connect(void);
68
69 static void
70 zclient_connect(void)
71 {
72   int ret;
73
74   union {
75     struct sockaddr_in sin;
76     struct sockaddr_un sun;
77   } sockaddr;
78
79   if (close(zebra.sock) < 0)
80     olsr_exit("QUAGGA: Could not close socket", EXIT_FAILURE);
81
82   zebra.sock = socket(zebra.port ? AF_INET : AF_UNIX, SOCK_STREAM, 0);
83
84   if (zebra.sock < 0)
85     olsr_exit("QUAGGA: Could not create socket", EXIT_FAILURE);
86
87   memset(&sockaddr, 0, sizeof sockaddr);
88
89   if (zebra.port) {
90     sockaddr.sin.sin_family = AF_INET;
91     sockaddr.sin.sin_port = htons(zebra.port);
92     sockaddr.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
93     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sin, sizeof sockaddr.sin);
94   } else {
95     sockaddr.sun.sun_family = AF_UNIX;
96     strscpy(sockaddr.sun.sun_path, zebra.sockpath, sizeof(sockaddr.sun.sun_path));
97     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sun, sizeof sockaddr.sun);
98   }
99
100   if (ret < 0)
101     zebra.status &= ~STATUS_CONNECTED;
102   else
103     zebra.status |= STATUS_CONNECTED;
104
105 }
106
107 void
108 zclient_reconnect(void)
109 {
110   struct rt_entry *tmp;
111
112   zclient_connect();
113   if (!(zebra.status & STATUS_CONNECTED))
114     return;                     // try again next time
115
116   zebra_hello(ZEBRA_HELLO);
117   if (zebra.options & OPTION_EXPORT) {
118     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
119       zebra_addroute(tmp);
120     }
121     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
122   }
123   zebra_redistribute(ZEBRA_REDISTRIBUTE_ADD);
124
125 }
126
127 int
128 zclient_write(unsigned char *options)
129 {
130   unsigned char *pnt;
131   uint16_t len;
132   int ret;
133
134   if (!(zebra.status & STATUS_CONNECTED))
135     return 0;
136
137   pnt = options;
138   memcpy(&len, pnt, sizeof len);
139
140   len = ntohs(len);
141
142   do {
143     ret = write(zebra.sock, pnt, len);
144     if (ret < 0) {
145       if ((errno == EINTR) || (errno == EAGAIN)) {
146         errno = 0;
147         ret = 0;
148         continue;
149       } else {
150         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra.\n");
151         zebra.status &= ~STATUS_CONNECTED;
152         /* TODO: Remove HNAs added from redistribution */
153         free(options);
154         return -1;
155       }
156     }
157     pnt = pnt + ret;
158   }
159   while ((len -= ret));
160   free(options);
161
162   return 0;
163 }
164
165 unsigned char *
166 zclient_read(ssize_t * size)
167 {
168   unsigned char *buf = NULL;
169   ssize_t bufsize = 0;
170   uint16_t offset = 0;
171   int socket_flags_saved = fcntl(zebra.sock, F_GETFL);
172
173   /* initialise size */
174   *size = 0;
175
176   /* set non-blocking on the socket */
177   (void) fcntl(zebra.sock, F_SETFL, socket_flags_saved | O_NONBLOCK);
178
179   /* read complete packets */
180   do {
181     ssize_t bytes_received;
182     uint16_t packet_length;
183
184     /* (re)allocate buffer */
185     if (*size == bufsize) {
186       ssize_t start = bufsize;
187       bufsize += AUTOBUFCHUNK;
188       buf = olsr_realloc(buf, bufsize, "QUAGGA: grow read buffer");
189       memset(&buf[start], 0, AUTOBUFCHUNK);
190     }
191
192     /* read from socket */
193     bytes_received = read(zebra.sock, &buf[*size], bufsize - *size);
194
195     /* handle invalid packet */
196     if (!bytes_received) {
197       goto error_out;
198     }
199
200     /* handle no data available */
201     if (bytes_received < 0) {
202       /* handle disconnect */
203       if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { // oops - we got disconnected
204         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
205         zebra.status &= ~STATUS_CONNECTED;
206         /* TODO: Remove HNAs added from redistribution */
207       }
208
209       goto error_out;
210     }
211
212     *size += bytes_received;
213
214     /* detect zebra packet fragmentation */
215     while (*size >= (ssize_t) (offset + sizeof(packet_length))) {
216       packet_length = ntohs(*((uint16_t *) &buf[offset]));
217       offset += packet_length;
218     }
219   } while (*size != offset);
220
221   out: (void) fcntl(zebra.sock, F_SETFL, socket_flags_saved);
222   return buf;
223
224   error_out: free(buf);
225   buf = NULL;
226   *size = 0;
227   goto out;
228 }
229
230 /*
231  * Local Variables:
232  * c-basic-offset: 2
233  * indent-tabs-mode: nil
234  * End:
235  */