stream-tcp, stream-ssl: Remove unneeded getsockname() calls.
[cascardo/ovs.git] / lib / stream-tcp.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "stream.h"
19 #include <errno.h>
20 #include <inttypes.h>
21 #include <sys/types.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <netdb.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29 #include "dynamic-string.h"
30 #include "packets.h"
31 #include "socket-util.h"
32 #include "util.h"
33 #include "stream-provider.h"
34 #include "stream-fd.h"
35 #include "vlog.h"
36
37 VLOG_DEFINE_THIS_MODULE(stream_tcp);
38
39 /* Active TCP. */
40
41 static int
42 new_tcp_stream(const char *name, int fd, int connect_status,
43                struct stream **streamp)
44 {
45     int on = 1;
46     int retval;
47
48     retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);
49     if (retval) {
50         int error = sock_errno();
51         VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s",
52                  name, sock_strerror(error));
53         closesocket(fd);
54         return error;
55     }
56
57     return new_fd_stream(name, fd, connect_status, streamp);
58 }
59
60 static int
61 tcp_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
62 {
63     int fd, error;
64
65     error = inet_open_active(SOCK_STREAM, suffix, 0, NULL, &fd, dscp);
66     if (fd >= 0) {
67         return new_tcp_stream(name, fd, error, streamp);
68     } else {
69         VLOG_ERR("%s: connect: %s", name, ovs_strerror(error));
70         return error;
71     }
72 }
73
74 const struct stream_class tcp_stream_class = {
75     "tcp",                      /* name */
76     true,                       /* needs_probes */
77     tcp_open,                   /* open */
78     NULL,                       /* close */
79     NULL,                       /* connect */
80     NULL,                       /* recv */
81     NULL,                       /* send */
82     NULL,                       /* run */
83     NULL,                       /* run_wait */
84     NULL,                       /* wait */
85 };
86
87 #ifdef _WIN32
88 static int
89 windows_open(const char *name, char *suffix, struct stream **streamp,
90              uint8_t dscp)
91 {
92     int error, port;
93     FILE *file;
94     char *suffix_new, *path;
95
96     /* If the path does not contain a ':', assume it is relative to
97      * OVS_RUNDIR. */
98     if (!strchr(suffix, ':')) {
99         path = xasprintf("%s/%s", ovs_rundir(), suffix);
100     } else {
101         path = xstrdup(suffix);
102     }
103
104     file = fopen(path, "r");
105     if (!file) {
106         error = errno;
107         VLOG_DBG("%s: could not open %s (%s)", name, suffix,
108                  ovs_strerror(error));
109         return error;
110     }
111
112     error = fscanf(file, "%d", &port);
113     if (error != 1) {
114         VLOG_ERR("failed to read port from %s", suffix);
115         fclose(file);
116         return EINVAL;
117     }
118     fclose(file);
119
120     suffix_new = xasprintf("127.0.0.1:%d", port);
121
122     error = tcp_open(name, suffix_new, streamp, dscp);
123
124     free(suffix_new);
125     free(path);
126     return error;
127 }
128
129 const struct stream_class windows_stream_class = {
130     "unix",                     /* name */
131     false,                      /* needs_probes */
132     windows_open,                  /* open */
133     NULL,                       /* close */
134     NULL,                       /* connect */
135     NULL,                       /* recv */
136     NULL,                       /* send */
137     NULL,                       /* run */
138     NULL,                       /* run_wait */
139     NULL,                       /* wait */
140 };
141 #endif
142 \f
143 /* Passive TCP. */
144
145 static int ptcp_accept(int fd, const struct sockaddr_storage *,
146                        size_t, struct stream **streamp);
147
148 static int
149 new_pstream(char *suffix, const char *name, struct pstream **pstreamp,
150             int dscp, char *unlink_path, bool kernel_print_port)
151 {
152     char bound_name[SS_NTOP_BUFSIZE + 16];
153     char addrbuf[SS_NTOP_BUFSIZE];
154     struct sockaddr_storage ss;
155     int error;
156     uint16_t port;
157     int fd;
158     char *conn_name = CONST_CAST(char *, name);
159
160     fd = inet_open_passive(SOCK_STREAM, suffix, -1, &ss, dscp,
161                            kernel_print_port);
162     if (fd < 0) {
163         return -fd;
164     }
165
166     port = ss_get_port(&ss);
167     if (!conn_name) {
168         snprintf(bound_name, sizeof bound_name, "ptcp:%"PRIu16":%s",
169                  port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
170         conn_name = bound_name;
171     }
172
173     error = new_fd_pstream(conn_name, fd, ptcp_accept, set_dscp, unlink_path,
174                            pstreamp);
175     if (!error) {
176         pstream_set_bound_port(*pstreamp, htons(port));
177     }
178     return error;
179 }
180
181 static int
182 ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
183           uint8_t dscp)
184 {
185     return new_pstream(suffix, NULL, pstreamp, dscp, NULL, true);
186 }
187
188 static int
189 ptcp_accept(int fd, const struct sockaddr_storage *ss,
190             size_t ss_len OVS_UNUSED, struct stream **streamp)
191 {
192     char name[SS_NTOP_BUFSIZE + 16];
193     char addrbuf[SS_NTOP_BUFSIZE];
194
195     snprintf(name, sizeof name, "tcp:%s:%"PRIu16,
196              ss_format_address(ss, addrbuf, sizeof addrbuf),
197              ss_get_port(ss));
198     return new_tcp_stream(name, fd, 0, streamp);
199 }
200
201 const struct pstream_class ptcp_pstream_class = {
202     "ptcp",
203     true,
204     ptcp_open,
205     NULL,
206     NULL,
207     NULL,
208     NULL,
209 };
210
211 #ifdef _WIN32
212 static int
213 pwindows_open(const char *name, char *suffix, struct pstream **pstreamp,
214               uint8_t dscp)
215 {
216     int error;
217     char *suffix_new, *path;
218     FILE *file;
219     struct pstream *listener;
220
221     suffix_new = xstrdup("0:127.0.0.1");
222
223     /* If the path does not contain a ':', assume it is relative to
224      * OVS_RUNDIR. */
225     if (!strchr(suffix, ':')) {
226         path = xasprintf("%s/%s", ovs_rundir(), suffix);
227     } else {
228         path = xstrdup(suffix);
229     }
230
231     error = new_pstream(suffix_new, name, pstreamp, dscp, path, false);
232     if (error) {
233         goto exit;
234     }
235     listener = *pstreamp;
236
237     file = fopen(path, "w");
238     if (!file) {
239         error = errno;
240         VLOG_DBG("could not open %s (%s)", path, ovs_strerror(error));
241         goto exit;
242     }
243
244     fprintf(file, "%d\n", ntohs(listener->bound_port));
245     if (fflush(file) == EOF) {
246         error = EIO;
247         VLOG_ERR("write failed for %s", path);
248         fclose(file);
249         goto exit;
250     }
251     fclose(file);
252
253 exit:
254     free(suffix_new);
255     return error;
256 }
257
258 const struct pstream_class pwindows_pstream_class = {
259     "punix",
260     false,
261     pwindows_open,
262     NULL,
263     NULL,
264     NULL,
265     NULL,
266 };
267 #endif