Merge redistribute add and delete functions
[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-2010 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   if (zebra.options & OPTION_EXPORT) {
99     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
100       zebra_addroute(tmp);
101     }
102     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
103   }
104   zebra_redistribute(ZEBRA_REDISTRIBUTE_ADD);
105
106 }
107
108 int
109 zclient_write(unsigned char *options)
110 {
111   unsigned char *pnt;
112   uint16_t len;
113   int ret;
114
115   if (!(zebra.status & STATUS_CONNECTED))
116     return 0;
117
118   pnt = options;
119   memcpy(&len, pnt, sizeof len);
120
121   len = ntohs(len);
122
123   do {
124     ret = write(zebra.sock, pnt, len);
125     if (ret < 0) {
126       if ((errno == EINTR) || (errno == EAGAIN)) {
127         errno = 0;
128         ret = 0;
129         continue;
130       } else {
131         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra.\n");
132         zebra.status &= ~STATUS_CONNECTED;
133         /* TODO: Remove HNAs added from redistribution */
134         free(options);
135         return -1;
136       }
137     }
138     pnt = pnt + ret;
139   }
140   while ((len -= ret));
141   free(options);
142
143   return 0;
144 }
145
146 unsigned char *
147 zclient_read(ssize_t * size)
148 {
149   unsigned char *buf;
150   ssize_t bytes, bufsize;
151   uint16_t length, offset;
152   int sockstatus;
153
154   /* initialize variables */
155   buf = NULL;
156   offset = 0;
157   *size = 0;
158   bufsize = 0;
159
160   /* save socket status and set non-blocking for read */
161   sockstatus = fcntl(zebra.sock, F_GETFL);
162   fcntl(zebra.sock, F_SETFL, sockstatus|O_NONBLOCK);
163
164   /* read whole packages */
165   do {
166
167     /* (re)allocate buffer */
168     if (*size == bufsize) {
169       bufsize += BUFSIZE;
170       buf = my_realloc(buf, bufsize, "QUAGGA: Grow read buffer");
171     }
172
173     /* read from socket */
174     bytes = read(zebra.sock, buf + *size, bufsize - *size);
175     /* handle broken packet */
176     if (!bytes) {
177       free(buf);
178       return NULL;
179     }
180     /* handle no data available */
181     if (bytes < 0) {
182       /* handle disconnect */
183       if (errno != EAGAIN) {    // oops - we got disconnected
184         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
185         zebra.status &= ~STATUS_CONNECTED;
186         /* TODO: Remove HNAs added from redistribution */
187       }
188       free(buf);
189       return NULL;
190     }
191
192     *size += bytes;
193
194     /* detect zebra packet fragmentation */
195     do {
196       memcpy(&length, buf + offset, sizeof length);
197       length = ntohs(length);
198       offset += length;
199     }
200     while (*size >= (ssize_t) (offset + sizeof length));
201     /* set blocking socket on fragmented packet */
202     if (*size != offset)
203       fcntl(zebra.sock, F_SETFL, sockstatus);
204
205   }
206   while (*size != offset);
207
208   /* restore socket status */
209   fcntl(zebra.sock, F_SETFL, sockstatus);
210
211   return buf;
212 }
213
214 /*
215  * Local Variables:
216  * c-basic-offset: 2
217  * indent-tabs-mode: nil
218  * End:
219  */