]> git.ipfire.org Git - people/ms/rstp.git/blob - ctl_socket.c
Initial commit
[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
35 #include "epoll_loop.h"
36 #include "log.h"
37
38
39 int server_socket(void)
40 {
41 struct sockaddr_un sa;
42 int s;
43
44 TST (strlen(RSTP_SERVER_SOCK_NAME) < sizeof(sa.sun_path), -1);
45
46 s = socket(PF_UNIX, SOCK_DGRAM, 0);
47 if (s < 0) {
48 ERROR("Couldn't open unix socket: %m");
49 return -1;
50 }
51
52 set_socket_address(&sa, RSTP_SERVER_SOCK_NAME);
53
54 if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
55 ERROR("Couldn't bind socket: %m");
56 close(s);
57 return -1;
58 }
59
60 return s;
61 }
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_state);
69 SERVER_MESSAGE_CASE(set_bridge_config);
70 SERVER_MESSAGE_CASE(get_port_state);
71 SERVER_MESSAGE_CASE(set_port_config);
72 SERVER_MESSAGE_CASE(set_debug_level);
73
74 default:
75 ERROR("CTL: Unknown command %d", cmd);
76 return -1;
77 }
78 }
79
80 #define msg_buf_len 1024
81 unsigned char msg_inbuf[1024];
82 unsigned char msg_outbuf[1024];
83
84 void ctl_rcv_handler(uint32_t events, struct epoll_event_handler *p)
85 {
86 struct ctl_msg_hdr mhdr;
87 struct msghdr msg;
88 struct sockaddr_un sa;
89 struct iovec iov[2];
90 int l;
91
92 msg.msg_name = &sa; msg.msg_namelen = sizeof(sa);
93 msg.msg_iov = iov; msg.msg_iovlen = 2;
94 msg.msg_control = NULL; msg.msg_controllen = 0;
95 iov[0].iov_base = &mhdr; iov[0].iov_len = sizeof(mhdr);
96 iov[1].iov_base = msg_inbuf; iov[1].iov_len = msg_buf_len;
97 l = recvmsg(p->fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT);
98 TST(l > 0, );
99 if (msg.msg_flags != 0 || l < sizeof(mhdr) ||
100 l != sizeof(mhdr) + mhdr.lin ||
101 mhdr.lout > msg_buf_len || mhdr.cmd < 0) {
102 ERROR("CTL: Unexpected message. Ignoring");
103 return;
104 }
105
106
107 if (mhdr.lout)
108 mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin,
109 msg_outbuf, &mhdr.lout);
110 else
111 mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin,
112 NULL, NULL);
113
114 if (mhdr.res < 0)
115 mhdr.lout = 0;
116 iov[1].iov_base = msg_outbuf; iov[1].iov_len = mhdr.lout;
117 l = sendmsg(p->fd, &msg, MSG_NOSIGNAL);
118 if (l < 0)
119 ERROR("CTL: Couldn't send response: %m");
120 else if (l != sizeof(mhdr) + mhdr.lout) {
121 ERROR("CTL: Couldn't send full response, sent %d bytes instead of %zd.",
122 l, sizeof(mhdr) + mhdr.lout);
123 }
124 }
125
126 struct epoll_event_handler ctl_handler;
127
128 int ctl_socket_init(void)
129 {
130 int s = server_socket();
131 if (s < 0)
132 return -1;
133
134 ctl_handler.fd = s;
135 ctl_handler.handler = ctl_rcv_handler;
136
137 TST(add_epoll(&ctl_handler) == 0, -1);
138 return 0;
139 }
140
141 void ctl_socket_cleanup(void)
142 {
143 remove_epoll(&ctl_handler);
144 close(ctl_handler.fd);
145 }