ICP  1
isisds_command.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include "isisds_command.h"
3 
4 // versions of these structures
5 // increment major for incompatible changes
6 // increment minor for backward compatible changes on server
7 #define ISISDS_MAJOR_VER 1
8 #define ISISDS_MINOR_VER 1
9 
10 #ifndef _WIN32
11 #define closesocket close
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/socket.h>
16 #include <netdb.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #endif
22 
23 // try to align to 64 bit (8 bytes) boundaries
24 typedef struct
25 {
26  int len;
27  int ver_major;
28  int ver_minor;
29  int pid;
30  int access_type; // 0 =dae, 1 = crpt
31  int pad[1];
32  char user[32];
33  char host[64];
35 
36 // used for sends and replies once a connection open
37 // try to align to 64 bits (8 bytes) boundaries
38 typedef struct
39 {
40  int len; // of this structure plus any additional data (in bytes)
41  int type; // ISISDSDataType
42  int ndims;
43  int dims_array[11];
44  char command[32];
45  // additional data (if any) will follow this
47 
48 // wait until read len bytes, return <=0 on error
49 static int recv_all(SOCKET s, char* buffer, int len, int flags)
50 {
51  int n, ntot;
52  ntot = 0;
53  while(len > 0)
54  {
55  n = recv(s, buffer, len, flags);
56  if (n <= 0)
57  {
58  return n; /* error */
59  }
60  len -= n;
61  buffer += n;
62  ntot += n;
63  }
64  return ntot;
65 }
66 
67 // clear out old data from a socket
68 static void clear_replies(SOCKET s)
69 {
70  static char buffer[100000];
71  struct timeval timeout = { 0, 0 };
72  fd_set fds;
73  int done = 0;
74  while(!done)
75  {
76  FD_ZERO(&fds);
77  FD_SET(s, &fds);
78  if ( (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) && FD_ISSET(s, &fds) )
79  {
80  recv(s, buffer, sizeof(buffer), 0);
81  }
82  else
83  {
84  done = 1;
85  }
86  }
87 }
88 
89 // client: open a socket and perform initial negotiation
90 // return connected socket or INVALID_SOCKET on error
91 SOCKET isisds_send_open(const char* host, ISISDSAccessMode access_type)
92 {
93  SOCKET s;
94  int setkeepalive = 1;
95  struct hostent *hostp;
96  struct sockaddr_in address;
97  int n;
98  char *comm, *comm_data;
99 // int len_comm_data;
100  isisds_open_t op;
101  ISISDSDataType data_type;
102  int dims_array[10], ndims;
103 
104  if ( (hostp = gethostbyname(host)) == NULL )
105  {
106  return INVALID_SOCKET;
107  }
108  memset(&address, 0, sizeof(address));
109  memcpy(&(address.sin_addr.s_addr), hostp->h_addr_list[0], hostp->h_length);
110  address.sin_family = AF_INET;
111  address.sin_port = htons(ISISDS_PORT);
112  s = socket(PF_INET, SOCK_STREAM, 0);
113  if (s == INVALID_SOCKET)
114  {
115  return INVALID_SOCKET;
116  }
117  setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&setkeepalive, sizeof(setkeepalive));
118  if (connect(s, (struct sockaddr*)&address, sizeof(address)) == -1)
119  {
120  closesocket(s);
121  return INVALID_SOCKET;
122  }
123 // socket connected
126  op.pid = 0;
127  op.access_type = access_type;
128  strncpy(op.user, "faa", sizeof(op.user));
129  strncpy(op.host, "localhost", sizeof(op.host));
130  op.len = sizeof(op);
131  if ( (n = send(s, (char*)&op, sizeof(op), 0)) != sizeof(op) )
132  {
133  closesocket(s);
134  return INVALID_SOCKET;
135  }
136  if (isisds_recv_command_alloc(s, &comm, (void**)&comm_data, &data_type, dims_array, &ndims) <= 0)
137  {
138  closesocket(s);
139  return INVALID_SOCKET;
140  }
141  if (comm_data != NULL)
142  {
143  free(comm_data);
144  }
145  if (!strcmp(comm, "OK"))
146  {
147  free(comm);
148  return s;
149  }
150  else
151  {
152  free(comm);
153  closesocket(s);
154  return INVALID_SOCKET;
155  }
156 }
157 
158 // server
159 // client minor ver <= server minor ver
161 {
162  int n;
163  isisds_open_t op;
164  if ( (n = recv_all(s, (char*)&op, sizeof(op), 0)) != sizeof(op) )
165  {
166  return -1;
167  }
168  if ( op.len != sizeof(op) )
169  {
170  return -1;
171  }
172  if ( (op.ver_major != ISISDS_MAJOR_VER) || (op.ver_minor > ISISDS_MINOR_VER) )
173  {
174  return -1;
175  }
176  *access_type = op.access_type;
177  return isisds_send_command(s, "OK", NULL, 0, NULL, 0);
178 }
179 
180 // return > 0 on success
181 // if dims_array == NULL, ndims is length
182 // on graceful termination should get an FD_CLOSE from client, should then send any data
183 // shutdown(s, SD_SEND) and then closesocket()
184 //
185 int isisds_send_command(SOCKET s, const char* command, const void* data, ISISDSDataType type, const int dims_array[], int ndims)
186 {
187  int i, n, len_data;
189  memset(&comm, 0, sizeof(comm));
190  if (dims_array == NULL)
191  {
192  comm.ndims = 1;
193  comm.dims_array[0] = ndims;
194  len_data = ndims * isisds_type_size[type];
195  }
196  else
197  {
198  len_data = 1;
199  comm.ndims = ndims;
200  for(i=0; i<ndims; i++)
201  {
202  len_data *= dims_array[i];
203  comm.dims_array[i] = dims_array[i];
204  }
205  len_data *= isisds_type_size[type];
206  }
207  comm.len = sizeof(comm) + len_data;
208  comm.type = type;
209  strncpy(comm.command, command, sizeof(comm.command));
210  clear_replies(s);
211  n = send(s, (char*)&comm, sizeof(comm), 0);
212  if ( (n == sizeof(comm)) && (data != NULL) && (len_data > 0) )
213  {
214  n = send(s, data, len_data, 0);
215  }
216  return n;
217 }
218 
219 // if not do_alloc, then type and dims_array are checked
220 static int isisds_recv_command_helper(SOCKET s, char** command, void** data, ISISDSDataType* type, int dims_array[], int* ndims, int do_alloc)
221 {
222  int n, len_data, size_in, i;
224  n = recv_all(s, (char*)&comm, sizeof(comm), 0);
225  if (n != sizeof(comm))
226  {
227  return -1;
228  }
229  *command = (char*)malloc(sizeof(comm.command) + 1);
230  strncpy(*command, comm.command, sizeof(comm.command));
231  (*command)[sizeof(comm.command)] = '\0';
232  len_data = comm.len - sizeof(comm); // in bytes
233  if (len_data < 0)
234  {
235  return -1; // error
236  }
237  else if (len_data == 0)
238  {
239  dims_array[0] = 0;
240  *ndims = 0;
241  *type = ISISDSUnknown;
242  return n; // all ok, just no extra data
243  }
244  isisds_report(0, 0, "Received data Type = \"%s\", ndims = %d\n", isisds_type_name[comm.type], comm.ndims);
245  if (do_alloc)
246  {
247  *data = malloc(len_data + 1);
248  ((char*)(*data))[len_data] = '\0';
249  }
250  else
251  {
252  size_in = 1;
253  for(i=0; i < *ndims; i++)
254  {
255  size_in *= dims_array[i];
256  }
257  size_in *= isisds_type_size[*type];
258  if (size_in < len_data)
259  {
260  return -1;
261  }
262  if (size_in > len_data) // only NULL terminate if space
263  {
264  ((char*)(*data))[len_data] = '\0';
265  }
266  }
267  n = recv_all(s, *data, len_data, 0);
268  if (n != len_data)
269  {
270  free(*data);
271  *data = NULL;
272  len_data = 0;
273  return -1;
274  }
275  // only update values if changed ... allows Read only parameters to be passed
276  if ( do_alloc || (*ndims != comm.ndims) )
277  {
278  *ndims = comm.ndims;
279  }
280  if ( do_alloc || (*type != comm.type) )
281  {
282  *type = comm.type;
283  }
284  for(i=0; i < comm.ndims; i++)
285  {
286  dims_array[i] = comm.dims_array[i];
287  }
288  return n;
289 }
290 
291 // return > 0 on success
292 int isisds_recv_command(SOCKET s, char* command, int* len_command, void* data, ISISDSDataType* type, int dims_array[], int* ndims)
293 {
294  int t_dims[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
295  int t_ndims = 1;
296  int istat;
297  char* command_temp = NULL;
298  if (type == NULL)
299  {
300  return -1;
301  }
302  if ( dims_array == NULL || ndims == NULL || (*ndims <= 1 && dims_array[0] <= 1) )
303  {
304  // assume single simple value
305  istat = isisds_recv_command_helper(s, &command_temp, &data, type, t_dims, &t_ndims, 0);
306  if ( (t_ndims != 1) || (t_dims[0] != 1) )
307  {
308  istat = -1;
309  }
310  }
311  else
312  {
313  istat = isisds_recv_command_helper(s, &command_temp, &data, type, dims_array, ndims, 0);
314  }
315  strncpy(command, command_temp, *len_command);
316  *len_command = strlen(command_temp);
317  free(command_temp);
318  return istat;
319 }
320 
321 // return > 0 on success
322 int isisds_recv_command_alloc(SOCKET s, char** command, void** data, ISISDSDataType* type, int dims_array[], int* ndims)
323 {
324  if (ndims == NULL || dims_array == NULL || type == NULL)
325  {
326  return -1;
327  }
328  if (data == NULL || command == NULL)
329  {
330  return -1;
331  }
332  *data = NULL;
333  *command = NULL;
334  *ndims = 0;
335  dims_array[0] = 0;
336  *type = ISISDSUnknown;
337  return isisds_recv_command_helper(s, command, data, type, dims_array, ndims, 1);
338 }
339 
341 {
342  // shutdown((*pfh)->s, SD_SEND); // indicate no more data to send SHUT_WR
343  // check for FD_READ and recv any other stuff from server
344  // check for FD_CLOSE and closesocket()
345  closesocket(s);
346  return 0;
347 }
348 
349 static void default_status_reporter(int status, int code, const char* message)
350 {
351  printf("ISISDS: %d %d %s\n", status, code, message);
352 }
353 
355 
356 int isisds_report(int status, int code, const char* format, ... )
357 {
358  va_list ap;
359  char* message = (char*)malloc(1024);
360  va_start(ap, format);
361  vsprintf(message, format, ap);
362  va_end(ap);
363  (*status_reporter)(status, code, message);
364  free(message);
365  return 0;
366 }
367 
369 {
370  status_reporter = report_func;
371  return 0;
372 }
#define ISISDS_PORT
Definition: isisds_command.h:6
static void clear_replies(SOCKET s)
static int isisds_recv_command_helper(SOCKET s, char **command, void **data, ISISDSDataType *type, int dims_array[], int *ndims, int do_alloc)
ISISDSDataType
static isisds_error_report_t status_reporter
#define ISISDS_MINOR_VER
Definition: isisds_command.c:8
int isisds_report(int status, int code, const char *format,...)
int isisds_send_command(SOCKET s, const char *command, const void *data, ISISDSDataType type, const int dims_array[], int ndims)
int isisds_recv_command(SOCKET s, char *command, int *len_command, void *data, ISISDSDataType *type, int dims_array[], int *ndims)
static void default_status_reporter(int status, int code, const char *message)
void(* isisds_error_report_t)(int status, int code, const char *messsage)
Definition: isisds_command.h:4
int isisds_send_close(SOCKET s)
#define INVALID_SOCKET
#define SOCKET
int isisds_set_report_func(isisds_error_report_t report_func)
static const char * isisds_type_name[]
ISISDSAccessMode
static int isisds_type_size[]
int isisds_recv_open(SOCKET s, ISISDSAccessMode *access_type)
#define closesocket
SOCKET isisds_send_open(const char *host, ISISDSAccessMode access_type)
static int recv_all(SOCKET s, char *buffer, int len, int flags)
#define ISISDS_MAJOR_VER
Definition: isisds_command.c:7
int isisds_recv_command_alloc(SOCKET s, char **command, void **data, ISISDSDataType *type, int dims_array[], int *ndims)