More descriptive messages
[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 "client.h"
33
34 static void *my_realloc(void *, size_t, const char *);
35 static void zclient_connect(void);
36
37 static void *
38 my_realloc(void *buf, size_t s, const char *c)
39 {
40
41   buf = realloc(buf, s);
42   if (!buf) {
43     OLSR_PRINTF(1, "(QUAGGA) Out of memory: %s!\n", strerror(errno));
44     olsr_syslog(OLSR_LOG_ERR, "(QUAGGA) Out of memory!\n");
45     olsr_exit(c, EXIT_FAILURE);
46   }
47
48   return buf;
49 }
50
51 static void
52 zclient_connect(void)
53 {
54   int ret;
55
56   union {
57     struct sockaddr_in sin;
58     struct sockaddr_un sun;
59   } sockaddr;
60
61   if (close(zebra.sock) < 0)
62     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
63   zebra.sock = socket(zebra.port ? AF_INET : AF_UNIX, SOCK_STREAM, 0);
64
65   if (zebra.sock < 0)
66     olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE);
67
68   memset(&sockaddr, 0, sizeof sockaddr);
69
70   if (zebra.port) {
71     sockaddr.sin.sin_family = AF_INET;
72     sockaddr.sin.sin_port = htons(zebra.port);
73     sockaddr.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
74     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sin, sizeof sockaddr.sin);
75   } else {
76     sockaddr.sun.sun_family = AF_UNIX;
77     strscpy(sockaddr.sun.sun_path, zebra.sockpath, sizeof(sockaddr.sun.sun_path));
78     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sun, sizeof sockaddr.sun);
79   }
80
81   if (ret < 0)
82     zebra.status &= ~STATUS_CONNECTED;
83   else
84     zebra.status |= STATUS_CONNECTED;
85
86 }
87
88 void
89 zclient_reconnect(void)
90 {
91   struct rt_entry *tmp;
92
93   zclient_connect();
94   if (!(zebra.status & STATUS_CONNECTED))
95     return;                     // try again next time
96
97   if (zebra.options & OPTION_EXPORT) {
98     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
99       zebra_addroute(tmp);
100     }
101     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
102   }
103   zebra_enable_redistribute();
104
105 }
106
107 int
108 zclient_write(unsigned char *options)
109 {
110   unsigned char *pnt;
111   uint16_t len;
112   int ret;
113
114   if (!(zebra.status & STATUS_CONNECTED))
115     return 0;
116
117   pnt = options;
118   memcpy(&len, pnt, sizeof len);
119
120   len = ntohs(len);
121
122   do {
123     ret = write(zebra.sock, pnt, len);
124     if (ret < 0) {
125       if ((errno == EINTR) || (errno == EAGAIN)) {
126         errno = 0;
127         ret = 0;
128         continue;
129       } else {
130         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra.\n");
131         zebra.status &= ~STATUS_CONNECTED;
132         /* TODO: Remove HNAs added from redistribution */
133         free(options);
134         return -1;
135       }
136     }
137     pnt = pnt + ret;
138   }
139   while ((len -= ret));
140   free(options);
141
142   return 0;
143 }
144
145 unsigned char *
146 zclient_read(ssize_t * size)
147 {
148   unsigned char *buf;
149   ssize_t bytes, bufsize;
150   uint16_t length, offset;
151   int sockstatus;
152
153   /* initialize variables */
154   buf = NULL;
155   offset = 0;
156   *size = 0;
157   bufsize = 0;
158
159   /* save socket status and set non-blocking for read */
160   sockstatus = fcntl(zebra.sock, F_GETFL);
161   fcntl(zebra.sock, F_SETFL, sockstatus|O_NONBLOCK);
162
163   /* read whole packages */
164   do {
165
166     /* (re)allocate buffer */
167     if (*size == bufsize) {
168       bufsize += BUFSIZE;
169       buf = my_realloc(buf, bufsize, "QUAGGA: Grow read buffer");
170     }
171
172     /* read from socket */
173     bytes = read(zebra.sock, buf + *size, bufsize - *size);
174     /* handle broken packet */
175     if (!bytes) {
176       free(buf);
177       return NULL;
178     }
179     /* handle no data available */
180     if (bytes < 0) {
181       /* handle disconnect */
182       if (errno != EAGAIN) {    // oops - we got disconnected
183         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
184         zebra.status &= ~STATUS_CONNECTED;
185         /* TODO: Remove HNAs added from redistribution */
186       }
187       free(buf);
188       return NULL;
189     }
190
191     *size += bytes;
192
193     /* detect zebra packet fragmentation */
194     do {
195       memcpy(&length, buf + offset, sizeof length);
196       length = ntohs(length);
197       offset += length;
198     }
199     while (*size >= (ssize_t) (offset + sizeof length));
200     /* set blocking socket on fragmented packet */
201     if (*size != offset)
202       fcntl(zebra.sock, F_SETFL, sockstatus);
203
204   }
205   while (*size != offset);
206
207   /* restore socket status */
208   fcntl(zebra.sock, F_SETFL, sockstatus);
209
210   return buf;
211 }
212
213 /*
214  * Local Variables:
215  * c-basic-offset: 2
216  * indent-tabs-mode: nil
217  * End:
218  */