Commit | Line | Data |
---|---|---|
0945b4fe | 1 | /* |
0945b4fe TH |
2 | * |
3 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | |
4 | */ | |
5 | ||
1e35d87d | 6 | #include <sys/socket.h> |
1e35d87d | 7 | |
8 | #include <string.h> | |
9 | ||
35dd0c2d | 10 | #include <arpa/inet.h> |
1e35d87d | 11 | #include <netdb.h> |
12 | #include <netinet/tcp.h> | |
13 | #include <unistd.h> | |
14 | ||
15 | #include "usbip_common.h" | |
0945b4fe TH |
16 | #include "usbip_network.h" |
17 | ||
18 | void pack_uint32_t(int pack, uint32_t *num) | |
19 | { | |
20 | uint32_t i; | |
21 | ||
22 | if (pack) | |
23 | i = htonl(*num); | |
24 | else | |
25 | i = ntohl(*num); | |
26 | ||
27 | *num = i; | |
28 | } | |
29 | ||
30 | void pack_uint16_t(int pack, uint16_t *num) | |
31 | { | |
32 | uint16_t i; | |
33 | ||
34 | if (pack) | |
35 | i = htons(*num); | |
36 | else | |
37 | i = ntohs(*num); | |
38 | ||
39 | *num = i; | |
40 | } | |
41 | ||
35dd0c2d | 42 | void pack_usb_device(int pack, struct usbip_usb_device *udev) |
0945b4fe TH |
43 | { |
44 | pack_uint32_t(pack, &udev->busnum); | |
45 | pack_uint32_t(pack, &udev->devnum); | |
46 | pack_uint32_t(pack, &udev->speed ); | |
47 | ||
48 | pack_uint16_t(pack, &udev->idVendor ); | |
49 | pack_uint16_t(pack, &udev->idProduct); | |
50 | pack_uint16_t(pack, &udev->bcdDevice); | |
51 | } | |
52 | ||
968c6595 | 53 | void pack_usb_interface(int pack __attribute__((unused)), |
35dd0c2d | 54 | struct usbip_usb_interface *udev __attribute__((unused))) |
0945b4fe TH |
55 | { |
56 | /* uint8_t members need nothing */ | |
57 | } | |
58 | ||
59 | ||
60 | static ssize_t usbip_xmit(int sockfd, void *buff, size_t bufflen, int sending) | |
61 | { | |
62 | ssize_t total = 0; | |
63 | ||
64 | if (!bufflen) | |
65 | return 0; | |
66 | ||
67 | do { | |
68 | ssize_t nbytes; | |
69 | ||
70 | if (sending) | |
71 | nbytes = send(sockfd, buff, bufflen, 0); | |
72 | else | |
73 | nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL); | |
74 | ||
75 | if (nbytes <= 0) | |
76 | return -1; | |
77 | ||
78 | buff = (void *) ((intptr_t) buff + nbytes); | |
79 | bufflen -= nbytes; | |
80 | total += nbytes; | |
81 | ||
82 | } while (bufflen > 0); | |
83 | ||
84 | ||
85 | return total; | |
86 | } | |
87 | ||
88 | ssize_t usbip_recv(int sockfd, void *buff, size_t bufflen) | |
89 | { | |
90 | return usbip_xmit(sockfd, buff, bufflen, 0); | |
91 | } | |
92 | ||
93 | ssize_t usbip_send(int sockfd, void *buff, size_t bufflen) | |
94 | { | |
95 | return usbip_xmit(sockfd, buff, bufflen, 1); | |
96 | } | |
97 | ||
98 | int usbip_send_op_common(int sockfd, uint32_t code, uint32_t status) | |
99 | { | |
100 | int ret; | |
101 | struct op_common op_common; | |
102 | ||
950a4cd8 | 103 | memset(&op_common, 0, sizeof(op_common)); |
0945b4fe | 104 | |
35dd0c2d | 105 | op_common.version = USBIP_VERSION; |
106 | op_common.code = code; | |
107 | op_common.status = status; | |
0945b4fe TH |
108 | |
109 | PACK_OP_COMMON(1, &op_common); | |
110 | ||
111 | ret = usbip_send(sockfd, (void *) &op_common, sizeof(op_common)); | |
112 | if (ret < 0) { | |
35dd0c2d | 113 | err("usbip_send has failed"); |
0945b4fe TH |
114 | return -1; |
115 | } | |
116 | ||
117 | return 0; | |
118 | } | |
119 | ||
120 | int usbip_recv_op_common(int sockfd, uint16_t *code) | |
121 | { | |
122 | int ret; | |
123 | struct op_common op_common; | |
124 | ||
950a4cd8 | 125 | memset(&op_common, 0, sizeof(op_common)); |
0945b4fe TH |
126 | |
127 | ret = usbip_recv(sockfd, (void *) &op_common, sizeof(op_common)); | |
128 | if (ret < 0) { | |
35dd0c2d | 129 | err("usbip_recv has failed ret=%d", ret); |
0945b4fe TH |
130 | goto err; |
131 | } | |
132 | ||
133 | PACK_OP_COMMON(0, &op_common); | |
134 | ||
135 | if (op_common.version != USBIP_VERSION) { | |
136 | err("version mismatch, %d %d", op_common.version, USBIP_VERSION); | |
137 | goto err; | |
138 | } | |
139 | ||
140 | switch(*code) { | |
141 | case OP_UNSPEC: | |
142 | break; | |
143 | default: | |
144 | if (op_common.code != *code) { | |
145 | info("unexpected pdu %d for %d", op_common.code, *code); | |
146 | goto err; | |
147 | } | |
148 | } | |
149 | ||
150 | if (op_common.status != ST_OK) { | |
151 | info("request failed at peer, %d", op_common.status); | |
152 | goto err; | |
153 | } | |
154 | ||
155 | *code = op_common.code; | |
156 | ||
157 | return 0; | |
158 | err: | |
159 | return -1; | |
160 | } | |
161 | ||
162 | ||
163 | int usbip_set_reuseaddr(int sockfd) | |
164 | { | |
165 | const int val = 1; | |
166 | int ret; | |
167 | ||
168 | ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); | |
169 | if (ret < 0) | |
170 | err("setsockopt SO_REUSEADDR"); | |
171 | ||
172 | return ret; | |
173 | } | |
174 | ||
175 | int usbip_set_nodelay(int sockfd) | |
176 | { | |
177 | const int val = 1; | |
178 | int ret; | |
179 | ||
180 | ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); | |
181 | if (ret < 0) | |
182 | err("setsockopt TCP_NODELAY"); | |
183 | ||
184 | return ret; | |
185 | } | |
186 | ||
187 | int usbip_set_keepalive(int sockfd) | |
188 | { | |
189 | const int val = 1; | |
190 | int ret; | |
191 | ||
192 | ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); | |
193 | if (ret < 0) | |
194 | err("setsockopt SO_KEEPALIVE"); | |
195 | ||
196 | return ret; | |
197 | } | |
198 | ||
0945b4fe | 199 | /* |
1e35d87d | 200 | * IPv6 Ready |
0945b4fe | 201 | */ |
1e35d87d | 202 | int usbip_net_tcp_connect(char *hostname, char *port) |
0945b4fe | 203 | { |
1e35d87d | 204 | struct addrinfo hints, *res, *rp; |
0945b4fe | 205 | int sockfd; |
1e35d87d | 206 | int ret; |
0945b4fe TH |
207 | |
208 | memset(&hints, 0, sizeof(hints)); | |
1e35d87d | 209 | hints.ai_family = AF_UNSPEC; |
0945b4fe TH |
210 | hints.ai_socktype = SOCK_STREAM; |
211 | ||
212 | /* get all possible addresses */ | |
1e35d87d | 213 | ret = getaddrinfo(hostname, port, &hints, &res); |
214 | if (ret < 0) { | |
215 | dbg("getaddrinfo: %s port %s: %s", hostname, port, | |
216 | gai_strerror(ret)); | |
217 | return ret; | |
0945b4fe TH |
218 | } |
219 | ||
1e35d87d | 220 | /* try the addresses */ |
221 | for (rp = res; rp; rp = rp->ai_next) { | |
222 | sockfd = socket(rp->ai_family, rp->ai_socktype, | |
223 | rp->ai_protocol); | |
224 | if (sockfd < 0) | |
0945b4fe | 225 | continue; |
0945b4fe TH |
226 | |
227 | /* should set TCP_NODELAY for usbip */ | |
228 | usbip_set_nodelay(sockfd); | |
1e35d87d | 229 | /* TODO: write code for heartbeat */ |
0945b4fe TH |
230 | usbip_set_keepalive(sockfd); |
231 | ||
1e35d87d | 232 | if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) |
233 | break; | |
0945b4fe | 234 | |
1e35d87d | 235 | close(sockfd); |
0945b4fe TH |
236 | } |
237 | ||
1e35d87d | 238 | if (!rp) |
239 | return EAI_SYSTEM; | |
0945b4fe | 240 | |
1e35d87d | 241 | freeaddrinfo(res); |
0945b4fe | 242 | |
1e35d87d | 243 | return sockfd; |
0945b4fe | 244 | } |