File Coverage

deps/libgit2/src/streams/socket.c
Criterion Covered Total %
statement 0 86 0.0
branch 0 44 0.0
condition n/a
subroutine n/a
pod n/a
total 0 130 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7              
8             #include "streams/socket.h"
9              
10             #include "posix.h"
11             #include "netops.h"
12             #include "registry.h"
13             #include "stream.h"
14              
15             #ifndef _WIN32
16             # include
17             # include
18             # include
19             # include
20             # include
21             # include
22             # include
23             #else
24             # include
25             # include
26             # ifdef _MSC_VER
27             # pragma comment(lib, "ws2_32")
28             # endif
29             #endif
30              
31             #ifdef GIT_WIN32
32             static void net_set_error(const char *str)
33             {
34             int error = WSAGetLastError();
35             char * win32_error = git_win32_get_error_message(error);
36              
37             if (win32_error) {
38             git_error_set(GIT_ERROR_NET, "%s: %s", str, win32_error);
39             git__free(win32_error);
40             } else {
41             git_error_set(GIT_ERROR_NET, "%s", str);
42             }
43             }
44             #else
45 0           static void net_set_error(const char *str)
46             {
47 0           git_error_set(GIT_ERROR_NET, "%s: %s", str, strerror(errno));
48 0           }
49             #endif
50              
51 0           static int close_socket(GIT_SOCKET s)
52             {
53 0 0         if (s == INVALID_SOCKET)
54 0           return 0;
55              
56             #ifdef GIT_WIN32
57             if (SOCKET_ERROR == closesocket(s))
58             return -1;
59              
60             if (0 != WSACleanup()) {
61             git_error_set(GIT_ERROR_OS, "winsock cleanup failed");
62             return -1;
63             }
64              
65             return 0;
66             #else
67 0           return close(s);
68             #endif
69              
70             }
71              
72 0           static int socket_connect(git_stream *stream)
73             {
74 0           struct addrinfo *info = NULL, *p;
75             struct addrinfo hints;
76 0           git_socket_stream *st = (git_socket_stream *) stream;
77 0           GIT_SOCKET s = INVALID_SOCKET;
78             int ret;
79              
80             #ifdef GIT_WIN32
81             /* on win32, the WSA context needs to be initialized
82             * before any socket calls can be performed */
83             WSADATA wsd;
84              
85             if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
86             git_error_set(GIT_ERROR_OS, "winsock init failed");
87             return -1;
88             }
89              
90             if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) {
91             WSACleanup();
92             git_error_set(GIT_ERROR_OS, "winsock init failed");
93             return -1;
94             }
95             #endif
96              
97 0           memset(&hints, 0x0, sizeof(struct addrinfo));
98 0           hints.ai_socktype = SOCK_STREAM;
99 0           hints.ai_family = AF_UNSPEC;
100              
101 0 0         if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) {
102 0           git_error_set(GIT_ERROR_NET,
103             "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret));
104 0           return -1;
105             }
106              
107 0 0         for (p = info; p != NULL; p = p->ai_next) {
108 0           s = socket(p->ai_family, p->ai_socktype | SOCK_CLOEXEC, p->ai_protocol);
109              
110 0 0         if (s == INVALID_SOCKET)
111 0           continue;
112              
113 0 0         if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
114 0           break;
115              
116             /* If we can't connect, try the next one */
117 0           close_socket(s);
118 0           s = INVALID_SOCKET;
119             }
120              
121             /* Oops, we couldn't connect to any address */
122 0 0         if (s == INVALID_SOCKET && p == NULL) {
    0          
123 0           git_error_set(GIT_ERROR_OS, "failed to connect to %s", st->host);
124 0           p_freeaddrinfo(info);
125 0           return -1;
126             }
127              
128 0           st->s = s;
129 0           p_freeaddrinfo(info);
130 0           return 0;
131             }
132              
133 0           static ssize_t socket_write(git_stream *stream, const char *data, size_t len, int flags)
134             {
135 0           git_socket_stream *st = (git_socket_stream *) stream;
136             ssize_t written;
137              
138 0           errno = 0;
139              
140 0 0         if ((written = p_send(st->s, data, len, flags)) < 0) {
141 0           net_set_error("error sending data");
142 0           return -1;
143             }
144              
145 0           return written;
146             }
147              
148 0           static ssize_t socket_read(git_stream *stream, void *data, size_t len)
149             {
150             ssize_t ret;
151 0           git_socket_stream *st = (git_socket_stream *) stream;
152              
153 0 0         if ((ret = p_recv(st->s, data, len, 0)) < 0)
154 0           net_set_error("error receiving socket data");
155              
156 0           return ret;
157             }
158              
159 0           static int socket_close(git_stream *stream)
160             {
161 0           git_socket_stream *st = (git_socket_stream *) stream;
162             int error;
163              
164 0           error = close_socket(st->s);
165 0           st->s = INVALID_SOCKET;
166              
167 0           return error;
168             }
169              
170 0           static void socket_free(git_stream *stream)
171             {
172 0           git_socket_stream *st = (git_socket_stream *) stream;
173              
174 0           git__free(st->host);
175 0           git__free(st->port);
176 0           git__free(st);
177 0           }
178              
179 0           static int default_socket_stream_new(
180             git_stream **out,
181             const char *host,
182             const char *port)
183             {
184             git_socket_stream *st;
185              
186 0 0         assert(out && host && port);
    0          
    0          
187              
188 0           st = git__calloc(1, sizeof(git_socket_stream));
189 0 0         GIT_ERROR_CHECK_ALLOC(st);
190              
191 0           st->host = git__strdup(host);
192 0 0         GIT_ERROR_CHECK_ALLOC(st->host);
193              
194 0 0         if (port) {
195 0           st->port = git__strdup(port);
196 0 0         GIT_ERROR_CHECK_ALLOC(st->port);
197             }
198              
199 0           st->parent.version = GIT_STREAM_VERSION;
200 0           st->parent.connect = socket_connect;
201 0           st->parent.write = socket_write;
202 0           st->parent.read = socket_read;
203 0           st->parent.close = socket_close;
204 0           st->parent.free = socket_free;
205 0           st->s = INVALID_SOCKET;
206              
207 0           *out = (git_stream *) st;
208 0           return 0;
209             }
210              
211 0           int git_socket_stream_new(
212             git_stream **out,
213             const char *host,
214             const char *port)
215             {
216 0           int (*init)(git_stream **, const char *, const char *) = NULL;
217 0           git_stream_registration custom = {0};
218             int error;
219              
220 0 0         assert(out && host && port);
    0          
    0          
221              
222 0 0         if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_STANDARD)) == 0)
223 0           init = custom.init;
224 0 0         else if (error == GIT_ENOTFOUND)
225 0           init = default_socket_stream_new;
226             else
227 0           return error;
228              
229 0 0         if (!init) {
230 0           git_error_set(GIT_ERROR_NET, "there is no socket stream available");
231 0           return -1;
232             }
233              
234 0           return init(out, host, port);
235             }