-
-
Notifications
You must be signed in to change notification settings - Fork 41
/
X32UDP.c
184 lines (172 loc) · 5.32 KB
/
X32UDP.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* X32UDP.c
* (POSIX compliant version, Linux... (Windows too))
* Created on: June 2, 2015
* Author: Patrick-Gilles Maillot
*
* Copyright 2015, Patrick-Gilles Maillot
* This software is distributed under he GNU GENERAL PUBLIC LICENSE.
*
* This software allows connecting to a remote X32 or XAIR system using
* UDP protocol; It provides a set of connect, send and receive functions.
* The receive mode is non-blocking, i.e. a timeout enables returning from
* the call even if no response is obtained by the server.
*
* Send and Receive buffers are provided by the caller. No provision is
* made in this package to keep or buffer data for deferred action or
* transfers.
*
* Note: This package was updated to use select() timeouts rather than
* calls to poll() to handle non-blocking IO.
*/
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#define BSIZE 512 // MAX receive buffer size
//
#ifdef __WIN32__
#include <winsock2.h>
WSADATA wsa;
struct sockaddr_in Xip;
int Xip_len = sizeof(Xip); // length of addresses
#else
#include <sys/socket.h>
#include <arpa/inet.h>
struct sockaddr_in Xip;
socklen_t Xip_len = sizeof(Xip); // length of addresses
#endif
//
struct sockaddr* Xip_addr = (struct sockaddr *)&Xip;
int Xfd; // X32 socket
fd_set ufd; // associted file descriptor
//
int r_len, p_status; // length and status for receiving
//
//
int X32Connect(char *Xip_str, char *Xport_str) {
//
// Initialize communication with X32 server at IP ip and PORT port//
// Load the X32 address we connect to; we're a client to X32, keep it simple.
//
// Input: String - Pointer to IP in the form "123.123.123.123"
// Input: String - Pointer to destination port in the form "12345"
//
// Returns int:
// -4 : (WIndows only) WSA init error
// -3 : Error on Sending data
// -2 : Socket creation error
// -1 : Error on waiting for data
// 0 : No error, no connection (timeout)
// 1 : Connected (connection validated with X32)
//
char r_buf[128]; // receive buffer for /info command test
char Info[8] = "/info"; // testing connection with /info request
struct timeval timeout;
#ifdef __WIN32__
//Initialize winsock
if (WSAStartup (MAKEWORD( 2, 2), &wsa) != 0) {
return -4; // Error on Windows sockets init
}
#endif
//
// Create UDP socket
if ((Xfd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
return -2; // An error occurred on socket creation
}
// Server sockaddr_in structure
memset (&Xip, 0, sizeof(Xip)); // Clear structure
Xip.sin_family = AF_INET; // Internet/IP
Xip.sin_addr.s_addr = inet_addr(Xip_str); // IP address
Xip.sin_port = htons(atoi(Xport_str)); // server port
timeout.tv_sec = 0; // Set timeout for non
timeout.tv_usec = 500000; // blocking recvfrom(): 500ms
// Validate connection by sending a /info command
if (sendto (Xfd, Info, 8, 0, Xip_addr, Xip_len) < 0) { // X32 sent something?
return (-3);
}
//register for receiving X32 console updates
FD_ZERO (&ufd);
FD_SET (Xfd, &ufd);
if ((p_status = select(Xfd+1, &ufd, NULL, NULL, &timeout)) > 0) {
r_len = recvfrom(Xfd, r_buf, 128, 0, 0, 0); // Get answer and
if ((strncmp(r_buf, Info, 5)) == 0) { // test data (5 bytes)
return 1; // Connected
}
} else if (p_status < 0) {
return -1; // Error on reading (not connected)
}
// Not connected on timeout after 500ms
return 0;
}
int X32Send(char *buffer, int lentgh) {
//
// Sends data to X32 server at IP and PORT previously set
// with X32Connect()
//
// Input: String - Pointer to data buffer to send
// Input: integer - Length of data in bytes
//
// Returns int:
// -1 : Error on Sending data
// >= 0 : Actual length of data sent, no error
//
// Just send data
return (sendto (Xfd, buffer, lentgh, 0, Xip_addr, Xip_len));
}
int X32Recv(char *buffer, int time_out) {
//
// Receives data from X32 server
//
// Input: String - Pointer to buffer to save data to,
// should be capable of receiving 512 bytes
// Input: integer - time_out (in us) for receiving data:
// depending on systems capabilities, positive and non-zero
// values may also result in no data (start with a value of 10ms)
//
// Returns int:
// -1 : Error on reading data
// 0 : No error, timeout reached or no data
// >0 : data length in the buffer
//
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = time_out; //Set timeout for non blocking recvfrom()
FD_ZERO (&ufd);
FD_SET (Xfd, &ufd); // X32 sent something?
if ((p_status = select(Xfd+1, &ufd, NULL, NULL, &timeout)) > 0) {
return recvfrom(Xfd, buffer, BSIZE, 0, 0, 0); // return length
} else if (p_status < 0) {
return -1; //An error occurred on polling
}
return 0; // No error, timeout
}
//
// Test purpose only - comment when linking the package to an application
//
#include <stdio.h>
int main() {
char r_buf[512];
char s_buf[] = {"/status\0"};
int r_len = 0;
int s_len = 0;
int ten_mills = 10000;
int status;
status = X32Connect("192.168.1.65", "10023");
printf ("Connection status: %d\n", status);
if (status) {
s_len = X32Send(s_buf, 8);
printf ("Send status: %d\n", s_len);
if (s_len) {
r_len = X32Recv(r_buf, ten_mills);
printf ("Recv status: %d\n", r_len);
s_len = 0;
while (r_len--) {
if (r_buf[s_len] < ' ') putchar('~');
else putchar(r_buf[s_len]);
s_len++;
}
putchar('\n');
}
}
return 0;
}