1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <arpa/inet.h>
16 #include <fcntl.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19
20 #include "common/admin_socket.h"
21 #include "common/errno.h"
22 #include "common/safe_io.h"
23 #include "common/admin_socket_client.h"
24
25 #include "include/compat.h"
26 #include "include/sock_compat.h"
27
28 using std::ostringstream;
29
30 const char* get_rand_socket_path()
31 {
32 static char *g_socket_path = NULL;
33
34 if (g_socket_path == NULL) {
35 char buf[512];
36 const char *tdir = getenv("TMPDIR");
37 if (tdir == NULL) {
38 tdir = "/tmp";
39 }
40 snprintf(buf, sizeof(((struct sockaddr_un*)0)->sun_path),
41 "%s/perfcounters_test_socket.%ld.%ld",
42 tdir, (long int)getpid(), time(NULL));
43 g_socket_path = (char*)strdup(buf);
44 }
45 return g_socket_path;
46 }
47
48 static std::string asok_connect(const std::string &path, int *fd)
49 {
(1) Event open_fn: |
Returning handle opened by "socket_cloexec". [details] |
(2) Event assign: |
Assigning: "socket_fd" = "socket_cloexec(1, SOCK_STREAM, 0)". |
Also see events: |
[noescape][noescape][noescape][assign] |
50 int socket_fd = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
(3) Event cond_false: |
Condition "socket_fd < 0", taking false branch. |
51 if(socket_fd < 0) {
52 int err = errno;
53 ostringstream oss;
54 oss << "socket(PF_UNIX, SOCK_STREAM, 0) failed: " << cpp_strerror(err);
55 return oss.str();
(4) Event if_end: |
End of if statement. |
56 }
57
58 struct sockaddr_un address;
59 memset(&address, 0, sizeof(struct sockaddr_un));
60 address.sun_family = AF_UNIX;
61 snprintf(address.sun_path, sizeof(address.sun_path), "%s", path.c_str());
62
(5) Event noescape: |
Resource "socket_fd" is not freed or pointed-to in function "connect". |
(6) Event cond_false: |
Condition "connect(socket_fd, (sockaddr *)&address, 110U /* sizeof (sockaddr_un) */) != 0", taking false branch. |
Also see events: |
[open_fn][assign][noescape][noescape][assign] |
63 if (::connect(socket_fd, (struct sockaddr *) &address,
64 sizeof(struct sockaddr_un)) != 0) {
65 int err = errno;
66 ostringstream oss;
67 oss << "connect(" << socket_fd << ") failed: " << cpp_strerror(err);
68 close(socket_fd);
69 return oss.str();
(7) Event if_end: |
End of if statement. |
70 }
71
72 struct timeval timer;
73 timer.tv_sec = 5;
74 timer.tv_usec = 0;
(8) Event noescape: |
Resource "socket_fd" is not freed or pointed-to in function "setsockopt". |
(9) Event cond_false: |
Condition "setsockopt(socket_fd, 1, 20, &timer, 16U /* sizeof (timer) */)", taking false branch. |
Also see events: |
[open_fn][assign][noescape][noescape][assign] |
75 if (::setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timer, sizeof(timer))) {
76 int err = errno;
77 ostringstream oss;
78 oss << "setsockopt(" << socket_fd << ", SO_RCVTIMEO) failed: "
79 << cpp_strerror(err);
80 close(socket_fd);
81 return oss.str();
(10) Event if_end: |
End of if statement. |
82 }
83 timer.tv_sec = 5;
84 timer.tv_usec = 0;
(11) Event noescape: |
Resource "socket_fd" is not freed or pointed-to in function "setsockopt". |
(12) Event cond_false: |
Condition "setsockopt(socket_fd, 1, 21, &timer, 16U /* sizeof (timer) */)", taking false branch. |
Also see events: |
[open_fn][assign][noescape][noescape][assign] |
85 if (::setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &timer, sizeof(timer))) {
86 int err = errno;
87 ostringstream oss;
88 oss << "setsockopt(" << socket_fd << ", SO_SNDTIMEO) failed: "
89 << cpp_strerror(err);
90 close(socket_fd);
91 return oss.str();
(13) Event if_end: |
End of if statement. |
92 }
93
94 *fd = socket_fd;
95 return "";
96 }
97
98 static std::string asok_request(int socket_fd, std::string request)
99 {
100 ssize_t res = safe_write(socket_fd, request.c_str(), request.length() + 1);
101 if (res < 0) {
102 int err = res;
103 ostringstream oss;
104 oss << "safe_write(" << socket_fd << ") failed to write request code: "
105 << cpp_strerror(err);
106 return oss.str();
107 }
108 return "";
109 }
110
111 AdminSocketClient::
112 AdminSocketClient(const std::string &path)
113 : m_path(path)
114 {
115 }
116
117 std::string AdminSocketClient::ping(bool *ok)
118 {
119 std::string version;
120 std::string result = do_request("{\"prefix\":\"0\"}", &version);
121 *ok = result == "" && version.length() == 1;
122 return result;
123 }
124
125 std::string AdminSocketClient::do_request(std::string request, std::string *result)
126 {
127 int socket_fd = 0, res;
128 std::string buffer;
129 uint32_t message_size_raw, message_size;
130
(1) Event open_arg: |
"asok_connect" opens handle stored into "socket_fd". [details] |
Also see events: |
[leaked_handle] |
131 std::string err = asok_connect(m_path, &socket_fd);
(2) Event cond_true: |
Condition "!err.empty()", taking true branch. |
132 if (!err.empty()) {
(3) Event goto: |
Jumping to label "out". |
133 goto out;
134 }
135 err = asok_request(socket_fd, request);
136 if (!err.empty()) {
137 goto done;
138 }
139 res = safe_read_exact(socket_fd, &message_size_raw,
140 sizeof(message_size_raw));
141 if (res < 0) {
142 int e = res;
143 ostringstream oss;
144 oss << "safe_read(" << socket_fd << ") failed to read message size: "
145 << cpp_strerror(e);
146 err = oss.str();
147 goto done;
148 }
149 message_size = ntohl(message_size_raw);
150 buffer.resize(message_size, 0);
151 res = safe_read_exact(socket_fd, &buffer[0], message_size);
152 if (res < 0) {
153 int e = res;
154 ostringstream oss;
155 oss << "safe_read(" << socket_fd << ") failed: " << cpp_strerror(e);
156 err = oss.str();
157 goto done;
158 }
159 //printf("MESSAGE FROM SERVER: %s\n", buffer.c_str());
160 std::swap(*result, buffer);
161 done:
162 close(socket_fd);
(4) Event label: |
Reached label "out". |
163 out:
(5) Event leaked_handle: |
Handle variable "socket_fd" going out of scope leaks the handle. |
Also see events: |
[open_arg] |
164 return err;
165 }
166