]> git.ipfire.org Git - people/ms/rstp.git/blob - ctl_socket.c
Merge remote-tracking branch 'upstream/master'
[people/ms/rstp.git] / ctl_socket.c
1 /*****************************************************************************
2 Copyright (c) 2006 EMC Corporation.
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2 of the License, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Authors: Srinivas Aji <Aji_Srinivas@emc.com>
22
23 ******************************************************************************/
24
25 #include "ctl_socket.h"
26 #include "ctl_socket_server.h"
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <stdarg.h>
35 #include <string.h>
36
37 #include "epoll_loop.h"
38 #include "log.h"
39
40 int server_socket(void)
41 {
42 struct sockaddr_un sa;
43 int s;
44
45 TST(strlen(RSTP_SERVER_SOCK_NAME) < sizeof(sa.sun_path), -1);
46
47 s = socket(PF_UNIX, SOCK_DGRAM, 0);
48 if (s < 0) {
49 ERROR("Couldn't open unix socket: %m");
50 return -1;
51 }
52
53 set_socket_address(&sa, RSTP_SERVER_SOCK_NAME);
54
55 if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
56 ERROR("Couldn't bind socket: %m");
57 close(s);
58 return -1;
59 }
60
61 return s;
62 }
63
64 int handle_message(int cmd, void *inbuf, int lin, void *outbuf, int lout)
65 {
66 switch (cmd) {
67 SERVER_MESSAGE_CASE(enable_bridge_rstp);
68 SERVER_MESSAGE_CASE(get_bridge_status);
69 SERVER_MESSAGE_CASE(set_bridge_config);
70 SERVER_MESSAGE_CASE(get_port_status);
71 SERVER_MESSAGE_CASE(set_port_config);
72 SERVER_MESSAGE_CASE(port_mcheck);
73 SERVER_MESSAGE_CASE(set_debug_level);
74
75 default:
76 ERROR("CTL: Unknown command %d", cmd);
77 return -1;
78 }
79 }
80
81 int ctl_in_handler = 0;
82 static unsigned char msg_logbuf[1024];
83 static unsigned int msg_log_offset;
84 void _ctl_err_log(char *fmt, ...)
85 {
86 if (msg_log_offset >= sizeof(msg_logbuf) - 1)
87 return;
88 int r;
89 va_list ap;
90 va_start(ap, fmt);
91 r = vsnprintf((char *)msg_logbuf + msg_log_offset,
92 sizeof(msg_logbuf) - msg_log_offset,
93 fmt, ap);
94 va_end(ap);
95 msg_log_offset += r;
96 if (msg_log_offset == sizeof(msg_logbuf)) {
97 msg_log_offset = sizeof(msg_logbuf) - 1;
98 msg_logbuf[sizeof(msg_logbuf) - 1] = 0;
99 }
100 }
101
102
103 #define msg_buf_len 1024
104 static unsigned char msg_inbuf[1024];
105 static unsigned char msg_outbuf[1024];
106
107 void ctl_rcv_handler(uint32_t events, struct epoll_event_handler *p)
108 {
109 struct ctl_msg_hdr mhdr;
110 struct msghdr msg;
111 struct sockaddr_un sa;
112 struct iovec iov[3];
113 int l;
114
115 msg.msg_name = &sa;
116 msg.msg_namelen = sizeof(sa);
117 msg.msg_iov = iov;
118 msg.msg_iovlen = 3;
119 msg.msg_control = NULL;
120 msg.msg_controllen = 0;
121 iov[0].iov_base = &mhdr;
122 iov[0].iov_len = sizeof(mhdr);
123 iov[1].iov_base = msg_inbuf;
124 iov[1].iov_len = msg_buf_len;
125 iov[2].iov_base = NULL;
126 iov[2].iov_len = 0;
127 l = recvmsg(p->fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT);
128 TST(l > 0,);
129 if (msg.msg_flags != 0 || l < sizeof(mhdr) ||
130 l != sizeof(mhdr) + mhdr.lin ||
131 mhdr.lout > msg_buf_len || mhdr.cmd < 0) {
132 ERROR("CTL: Unexpected message. Ignoring");
133 return;
134 }
135
136 msg_log_offset = 0;
137 ctl_in_handler = 1;
138
139 mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin,
140 msg_outbuf, mhdr.lout);
141
142 ctl_in_handler = 0;
143 if (mhdr.res < 0)
144 memset(msg_outbuf, 0, mhdr.lout);
145 if (msg_log_offset < mhdr.llog)
146 mhdr.llog = msg_log_offset;
147
148 iov[1].iov_base = msg_outbuf;
149 iov[1].iov_len = mhdr.lout;
150 iov[2].iov_base = msg_logbuf;
151 iov[2].iov_len = mhdr.llog;
152 l = sendmsg(p->fd, &msg, MSG_NOSIGNAL);
153 if (l < 0)
154 ERROR("CTL: Couldn't send response: %m");
155 else if (l != sizeof(mhdr) + mhdr.lout) {
156 ERROR
157 ("CTL: Couldn't send full response, sent %d bytes instead of %zd.",
158 l, sizeof(mhdr) + mhdr.lout);
159 }
160 }
161
162 struct epoll_event_handler ctl_handler;
163
164 int ctl_socket_init(void)
165 {
166 int s = server_socket();
167 if (s < 0)
168 return -1;
169
170 ctl_handler.fd = s;
171 ctl_handler.handler = ctl_rcv_handler;
172
173 TST(add_epoll(&ctl_handler) == 0, -1);
174 return 0;
175 }
176
177 void ctl_socket_cleanup(void)
178 {
179 remove_epoll(&ctl_handler);
180 close(ctl_handler.fd);
181 }