1 /*
2 * $Id: capi.c 1089 2012-03-27 02:23:05Z boote $
3 */
4 /************************************************************************
5 * *
6 * Copyright (C) 2002 *
7 * Internet2 *
8 * All Rights Reserved *
9 * *
10 ************************************************************************/
11 /*
12 * File: capi.c
13 *
14 * Author: Jeff W. Boote
15 * Internet2
16 *
17 * Date: Sun Jun 02 11:37:38 MDT 2002
18 *
19 * Description:
20 *
21 * This file contains the api functions that are typically called from
22 * an owamp client application.
23 */
24 #include <owamp/owampP.h>
25 #include <I2util/util.h>
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <netinet/in.h>
33 #include <string.h>
34 #include <assert.h>
35
36 /*
37 * Function: _OWPClientBind
38 *
39 * Description:
40 * This function attempts to bind the fd to a local address allowing
41 * the client socket to have the source addr bound.
42 *
43 * In Args:
44 *
45 * Out Args:
46 *
47 * Scope:
48 * Returns:
49 * True if successful, False if unsuccessful.
50 * Additionally err_ret will be set to OWPErrFATAL if there was a
51 * problem with the local_addr.
52 * Side Effect:
53 */
54 static OWPBoolean
_OWPClientBind(OWPControl cntrl,int fd,I2Addr local_addr,struct addrinfo * remote_addrinfo,OWPErrSeverity * err_ret)55 _OWPClientBind(
56 OWPControl cntrl,
57 int fd,
58 I2Addr local_addr,
59 struct addrinfo *remote_addrinfo,
60 OWPErrSeverity *err_ret
61 )
62 {
63 struct addrinfo *fai;
64 struct addrinfo *ai;
65
66 *err_ret = OWPErrOK;
67
68 if( !I2AddrSetSocktype(local_addr,SOCK_STREAM) ||
69 !I2AddrSetProtocol(local_addr,IPPROTO_TCP) ||
70 !(fai = I2AddrAddrInfo(local_addr,NULL,NULL))){
71 *err_ret = OWPErrFATAL;
72 return False;
73 }
74
75 /*
76 * Now that we have a valid addrinfo list for this address, go
77 * through each of those addresses and try to bind the first
78 * one that matches addr family and socktype.
79 */
80 for(ai=fai;ai;ai = ai->ai_next){
81 if(ai->ai_family != remote_addrinfo->ai_family)
82 continue;
83 if(ai->ai_socktype != remote_addrinfo->ai_socktype)
84 continue;
85
86 if(bind(fd,ai->ai_addr,ai->ai_addrlen) == 0){
87 if( I2AddrSetSAddr(local_addr,ai->ai_addr,ai->ai_addrlen)){
88 return True;
89 }
90 OWPError(cntrl->ctx,OWPErrFATAL,errno,
91 "I2AddrSetSAddr(): failed to set saddr");
92 return False;
93 }else{
94 switch(errno){
95 /* report these errors */
96 case EAGAIN:
97 case EBADF:
98 case ENOTSOCK:
99 case EADDRNOTAVAIL:
100 case EADDRINUSE:
101 case EACCES:
102 case EFAULT:
103 OWPError(cntrl->ctx,OWPErrFATAL,errno,
104 "bind(): %M");
105 break;
106 /* ignore all others */
107 default:
108 break;
109 }
110 return False;
111 }
112
113 }
114
115 /*
116 * None found.
117 */
118 return False;
119 }
120
121 /*
122 * Function: TryAddr
123 *
124 * Description:
125 * This function attempts to connect to the given ai description of
126 * the "server" addr possibly binding to "local" addr.
127 *
128 * In Args:
129 *
130 * Out Args:
131 *
132 * Scope:
133 * Returns:
134 * -1: error - future trys are unlikely to succeed - terminate upward.
135 * 0: success - wahoo!
136 * 1: keep trying - this one didn't work, probably addr mismatch.
137 * Side Effect:
138 */
139 /*
140 */
141 static int
TryAddr(OWPControl cntrl,struct addrinfo * ai,I2Addr local_addr,I2Addr server_addr)142 TryAddr(
143 OWPControl cntrl,
144 struct addrinfo *ai,
145 I2Addr local_addr,
146 I2Addr server_addr
147 )
148 {
149 OWPErrSeverity addr_ok=OWPErrOK;
150 int fd;
151
152 fd = socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol);
153 if(fd < 0)
154 return 1;
155
156 if(local_addr){
157 if(!_OWPClientBind(cntrl,fd,local_addr,ai,&addr_ok)){
158 if(addr_ok != OWPErrOK){
159 return -1;
160 }
161 goto cleanup;
162 }
163 }
164
165 /*
166 * Call connect - if it succeeds, return else try again.
167 */
168 if(connect(fd,ai->ai_addr,ai->ai_addrlen) == 0){
169
170 /*
171 * Connected, set the fields in the addr records
172 */
173 if(I2AddrSetSAddr(server_addr,ai->ai_addr,ai->ai_addrlen) &&
174 I2AddrSetSocktype(server_addr,ai->ai_socktype) &&
175 I2AddrSetProtocol(server_addr,ai->ai_protocol) &&
176 I2AddrSetFD(server_addr,fd,True)){
177
178 cntrl->remote_addr = server_addr;
179 cntrl->local_addr = local_addr;
180 cntrl->sockfd = fd;
181 return 0;
182 }
183
184 /*
185 * Connected, but addr record stuff failed.
186 */
187 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
188 "I2Addr functions failed after successful connection");
189 }
190
191 cleanup:
192 while((close(fd) < 0) && (errno == EINTR));
193 return 1;
194 }
195
196 /*
197 * Function: _OWPClientConnect
198 *
199 * Description:
200 * This function attempts to create a socket connection between
201 * the local client and the server. Each specified with OWPAddr
202 * records. If the local_addr is not specified, then the source
203 * addr is not bound. The server_addr is used to get a valid list
204 * of addrinfo records and each addrinfo description record is
205 * tried until one succeeds. (IPV6 is prefered over IPV4)
206 *
207 * In Args:
208 *
209 * Out Args:
210 *
211 * Scope:
212 * Returns:
213 * Side Effect:
214 */
215 static int
_OWPClientConnect(OWPControl cntrl,I2Addr local_addr,I2Addr server_addr,OWPErrSeverity * err_ret)216 _OWPClientConnect(
217 OWPControl cntrl,
218 I2Addr local_addr,
219 I2Addr server_addr,
220 OWPErrSeverity *err_ret
221 )
222 {
223 int rc;
224 struct addrinfo *fai=NULL;
225 struct addrinfo *ai=NULL;
226 char nodename[NI_MAXHOST];
227 size_t nodename_len = sizeof(nodename);
228 char servname[NI_MAXSERV];
229 size_t servname_len = sizeof(servname);
230 char *node,*serv;
231
232 if(!server_addr)
233 goto error;
234
235 /*
236 * Easy case - application provided socket directly.
237 */
238 if((cntrl->sockfd = I2AddrFD(server_addr)) > -1){
239 cntrl->remote_addr = server_addr;
240 return 0;
241 }
242
243 /*
244 * Initialize addrinfo portion of server_addr record.
245 */
246 if( !(fai = I2AddrAddrInfo(server_addr,NULL,OWP_CONTROL_SERVICE_NAME))){
247 goto error;
248 }
249
250 /*
251 * Now that we have addresses - see if it is valid by attempting
252 * to create a socket of that type, and binding(if wanted).
253 * Also check policy for allowed connection before calling
254 * connect.
255 */
256 if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv4Only)){
257 #ifdef AF_INET6
258 for(ai=fai;ai;ai=ai->ai_next){
259
260 if(ai->ai_family != AF_INET6) continue;
261
262 if( (rc = TryAddr(cntrl,ai,local_addr,server_addr)) == 0)
263 return 0;
264 if(rc < 0)
265 goto error;
266 }
267 }
268 #endif
269 /*
270 * Now try IPv4 addresses.
271 */
272 if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv6Only)){
273 for(ai=fai;ai;ai=ai->ai_next){
274
275 if(ai->ai_family != AF_INET) continue;
276
277 if( (rc = TryAddr(cntrl,ai,local_addr,server_addr)) == 0)
278 return 0;
279 if(rc < 0)
280 goto error;
281 }
282 }
283
284 error:
285 /*
286 * ifdef out for now... This should be detected by client tools
287 * that call OWPControlOpen and reported from there - otherwise
288 * retries put out too many error messages.
289 */
290 #if NOT
291 /*
292 * Unable to connect! If we have a server name report it in
293 * the error message.
294 */
295 if(I2AddrNodeName(server_addr,nodename,&nodename_len)){
296 node = nodename;
297 }
298 else
299 node = "**unknown**";
300
301 if(I2AddrServName(server_addr,servname,&servname_len)){
302 serv = servname;
303 }
304 else
305 serv = OWP_CONTROL_SERVICE_NAME;
306
307 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
308 "Unable to connect to \"[%s]:%s\"",node,serv);
309 #endif
310
311 *err_ret = OWPErrFATAL;
312
313 return -1;
314 }
315
316 /*
317 * Function: OWPControlOpen
318 *
319 * Description:
320 * Opens a connection to an owamp server. Returns after complete
321 * control connection setup is complete. This means that encrytion
322 * has been intialized, and the client is authenticated to the
323 * server if that is necessary. However, the client has not
324 * verified the server at this point.
325 *
326 * Returns:
327 * A valid OWPControl pointer or NULL.
328 * Side Effect:
329 */
330 OWPControl
OWPControlOpen(OWPContext ctx,I2Addr local_addr,I2Addr server_addr,uint32_t mode_req_mask,OWPUserID userid,OWPNum64 * uptime_ret,OWPErrSeverity * err_ret)331 OWPControlOpen(
332 OWPContext ctx, /* control context */
333 I2Addr local_addr, /* local addr or null */
334 I2Addr server_addr, /* server addr */
335 uint32_t mode_req_mask, /* requested modes */
336 OWPUserID userid, /* userid or NULL */
337 OWPNum64 *uptime_ret, /* server uptime - ret */
338 OWPErrSeverity *err_ret /* err - return */
339 )
340 {
341 int rc;
342 OWPControl cntrl;
343 uint32_t mode_avail;
344 uint8_t challenge[16];
345 uint8_t salt[_OWP_SALT_SIZE];
346 uint32_t count;
347 uint8_t token[_OWP_TOKEN_SIZE];
348 uint8_t *pf=NULL;
349 void *pf_free=NULL;
350 size_t pf_len=0;
351 OWPAcceptType acceptval;
352 OWPTimeStamp timestart,timeend;
353 OWPNum64 uptime;
354 int intr=1;
355 int *retn_on_intr = &intr;
356
357 *err_ret = OWPErrOK;
358
359 /*
360 * First allocate memory for the control state.
361 */
362 if( !(cntrl = _OWPControlAlloc(ctx,err_ret)))
363 goto error;
364
365 /*
366 * Use application defined I/O interrupt signal if available.
367 * (Default is to fail I/O if it is interrupted.)
368 */
369 if(cntrl->retn_on_intr){
370 retn_on_intr = cntrl->retn_on_intr;
371 }
372
373 /*
374 * Initialize server record for address we are connecting to.
375 */
376 if(!server_addr){
377 goto error;
378 }
379
380 /*
381 * Connect to the server.
382 * Address policy check happens in here.
383 */
384 if(_OWPClientConnect(cntrl,local_addr,server_addr,err_ret) != 0)
385 goto error;
386
387 if(!cntrl->local_addr){
388 if( !(cntrl->local_addr = I2AddrByLocalSockFD(
389 OWPContextErrHandle(cntrl->ctx),
390 cntrl->sockfd,False))){
391 goto error;
392 }
393 }
394
395 /*
396 * Read the server greating.
397 */
398 if((rc=_OWPReadServerGreeting(cntrl,retn_on_intr,&mode_avail,
399 challenge,salt,&count)) < OWPErrOK){
400 *err_ret = (OWPErrSeverity)rc;
401 goto error;
402 }
403
404 /*
405 * Select mode wanted...
406 */
407 mode_avail &= mode_req_mask; /* mask out unwanted modes */
408
409 /*
410 * retrieve pf if needed
411 */
412 if(userid && (mode_avail & OWP_MODE_DOCIPHER)){
413 strncpy(cntrl->userid_buffer,userid,
414 sizeof(cntrl->userid_buffer)-1);
415 if(_OWPCallGetPF(cntrl->ctx,cntrl->userid_buffer,
416 &pf,&pf_len,&pf_free,err_ret)){
417 cntrl->userid = cntrl->userid_buffer;
418 }
419 else{
420 if(*err_ret != OWPErrOK)
421 goto error;
422 }
423 }
424 /*
425 * If no pf, then remove auth/crypt modes
426 */
427 if(!pf)
428 mode_avail &= ~OWP_MODE_DOCIPHER;
429
430 /*
431 * Pick "highest" level mode still available to this server.
432 */
433 if((mode_avail & OWP_MODE_ENCRYPTED) &&
434 _OWPCallCheckControlPolicy(cntrl,OWP_MODE_ENCRYPTED,
435 cntrl->userid,
436 I2AddrSAddr(cntrl->local_addr,NULL),
437 I2AddrSAddr(cntrl->remote_addr,NULL),
438 err_ret)){
439 cntrl->mode = OWP_MODE_ENCRYPTED;
440 }
441 else if((*err_ret == OWPErrOK) &&
442 (mode_avail & OWP_MODE_AUTHENTICATED) &&
443 _OWPCallCheckControlPolicy(cntrl,OWP_MODE_AUTHENTICATED,
444 cntrl->userid,
445 I2AddrSAddr(cntrl->local_addr,NULL),
446 I2AddrSAddr(cntrl->remote_addr,NULL),
447 err_ret)){
448 cntrl->mode = OWP_MODE_AUTHENTICATED;
449 }
450 else if((*err_ret == OWPErrOK) &&
451 (mode_avail & OWP_MODE_OPEN) &&
452 _OWPCallCheckControlPolicy(cntrl,OWP_MODE_OPEN,cntrl->userid,
453 I2AddrSAddr(cntrl->local_addr,NULL),
454 I2AddrSAddr(cntrl->remote_addr,NULL),
455 err_ret)){
456 cntrl->mode = OWP_MODE_OPEN;
457 }
458 else if(*err_ret != OWPErrOK){
459 goto error;
460 }
461 else{
462 OWPError(ctx,OWPErrWARNING,OWPErrPOLICY,
463 "OWPControlOpen: No Common Modes");
464 goto denied;
465 }
466
467 /*
468 * Initialize all the encryption values as necessary.
469 */
470 if(cntrl->mode & OWP_MODE_DOCIPHER){
471 /*
472 * Create "token" for SetUpResponse message.
473 * Section 3.1 of owamp spec:
474 * AES(concat(challenge(16),aessession_key(16),hmackey(32)))
475 */
476 uint8_t buf[_OWP_TOKEN_SIZE];
477
478 /*
479 * Create random aes session key. Use rand data to
480 * initialize AES structures for use with this
481 * key. (ReadBlock/WriteBlock functions will automatically
482 * use this key for this cntrl connection.
483 */
484 if(I2RandomBytes(ctx->rand_src,cntrl->aessession_key,16) != 0)
485 goto error;
486 _OWPMakeKey(cntrl,cntrl->aessession_key);
487
488 /*
489 * Create random HMAC Session-key
490 * Initialize hmac structures with this key.
491 */
492 if(I2RandomBytes(ctx->rand_src,cntrl->hmac_key,
493 sizeof(cntrl->hmac_key)) != 0){
494 goto error;
495 }
496 I2HMACSha1Init(cntrl->send_hmac_ctx,cntrl->hmac_key,
497 sizeof(cntrl->hmac_key));
498 I2HMACSha1Init(cntrl->recv_hmac_ctx,cntrl->hmac_key,
499 sizeof(cntrl->hmac_key));
500
501 /*
502 * copy challenge
503 * concat session key to buffer
504 * concat hmac key to buffer
505 */
506 memcpy(buf,challenge,16);
507 memcpy(&buf[16],cntrl->aessession_key,16);
508 memcpy(&buf[32],cntrl->hmac_key,32);
509
510 /*
511 * Encrypt the token as specified by Section 3.1
512 * (AES CBC, IV=0, key=pbkdf2(pf))
513 */
514 if(OWPEncryptToken(pf,pf_len,salt,count,buf,token) != 0)
515 goto error;
516
517 /*
518 * Create random writeIV
519 */
520 if(I2RandomBytes(ctx->rand_src,cntrl->writeIV,16) != 0)
521 goto error;
522 }
523
524 if(pf_free){
525 /* clean-up */
526 memset(pf,0,pf_len);
527 free(pf_free);
528 pf_free = NULL;
529 pf = NULL;
530 pf_len = 0;
531 }
532
533 /*
534 * Get current time before sending client greeting - used
535 * for very rough estimate of RTT. (upper bound)
536 */
537 if(!OWPGetTimeOfDay(ctx,×tart))
538 goto error;
539
540 /*
541 * Write the client greeting, and see if the Server agree's to it.
542 */
543 if( ((rc=_OWPWriteSetupResponse(cntrl,retn_on_intr,token)) < OWPErrOK) ||
544 ((rc=_OWPReadServerStart(cntrl,retn_on_intr,&acceptval,
545 &uptime)) < OWPErrOK)){
546 *err_ret = (OWPErrSeverity)rc;
547 goto error;
548 }
549
550 /*
551 * TODO: enumerate reason for rejection
552 */
553 if(acceptval != OWP_CNTRL_ACCEPT){
554 char nodename_buf[255];
555 size_t nodename_buflen;
556
557 nodename_buflen = sizeof(nodename_buf);
558 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
559 "Server denied access: %s", I2AddrNodeName(server_addr, nodename_buf, &nodename_buflen));
560 goto denied;
561 }
562
563 /*
564 * Get current time after response from server and set the RTT
565 * in the "rtt_bound" field of cntrl.
566 */
567 if(!OWPGetTimeOfDay(ctx,&timeend))
568 goto error;
569
570 cntrl->rtt_bound = OWPNum64Sub(timeend.owptime,timestart.owptime);
571
572 if(uptime_ret){
573 *uptime_ret = uptime;
574 }
575
576 /*
577 * Done - return!
578 */
579 return cntrl;
580
581 /*
582 * If there was an error - set err_ret, then cleanup memory and return.
583 */
584 error:
585 *err_ret = OWPErrFATAL;
586
587 /*
588 * If access was denied - cleanup memory and return.
589 */
590 denied:
591 if(pf_free)
592 free(pf_free);
593 if(cntrl->local_addr != local_addr)
594 I2AddrFree(local_addr);
595 if(cntrl->remote_addr != server_addr)
596 I2AddrFree(server_addr);
597 OWPControlClose(cntrl);
598 return NULL;
599 }
600
601 /*
602 * Function: _OWPClientRequestTestReadResponse
603 *
604 * Description:
605 * This function is used to request a test from the server and
606 * return the response.
607 *
608 * In Args:
609 *
610 * Out Args:
611 *
612 * Scope:
613 * Returns:
614 * 0 on success
615 * Side Effect:
616 */
617 static int
_OWPClientRequestTestReadResponse(OWPControl cntrl,int * retn_on_intr,I2Addr sender,OWPBoolean server_conf_sender,I2Addr receiver,OWPBoolean server_conf_receiver,OWPTestSpec * test_spec,OWPSID sid,OWPErrSeverity * err_ret)618 _OWPClientRequestTestReadResponse(
619 OWPControl cntrl,
620 int *retn_on_intr,
621 I2Addr sender,
622 OWPBoolean server_conf_sender,
623 I2Addr receiver,
624 OWPBoolean server_conf_receiver,
625 OWPTestSpec *test_spec,
626 OWPSID sid, /* ret iff conf_receiver else set */
627 OWPErrSeverity *err_ret
628 )
629 {
630 int rc;
631 OWPAcceptType acceptval;
632 uint16_t port_ret=0;
633 uint8_t *sid_ret=NULL;
634 char nodename_buf[255];
635 size_t nodename_buflen;
636
637 if( (rc = _OWPWriteTestRequest(cntrl,retn_on_intr,
638 I2AddrSAddr(sender,NULL),
639 I2AddrSAddr(receiver,NULL),
640 server_conf_sender, server_conf_receiver,
641 sid, test_spec)) < OWPErrOK){
642 *err_ret = (OWPErrSeverity)rc;
643 return 1;
644 }
645
646 if(server_conf_receiver)
647 sid_ret = sid;
648
649 if((rc = _OWPReadAcceptSession(cntrl,retn_on_intr,&acceptval,
650 &port_ret,sid_ret)) < OWPErrOK){
651 *err_ret = (OWPErrSeverity)rc;
652 return 1;
653 }
654
655 /*
656 * Figure out if the server will be returning Port field.
657 * If so - set set_addr to the sockaddr that needs to be set.
658 */
659 if(server_conf_sender && !server_conf_receiver){
660 if( !I2AddrSetPort(sender,port_ret)){
661 return 1;
662 }
663 }
664 else if(!server_conf_sender && server_conf_receiver){
665 if( !I2AddrSetPort(receiver,port_ret)){
666 return 1;
667 }
668 }
669
670 if(acceptval == OWP_CNTRL_ACCEPT)
671 return 0;
672
673 /*
674 * TODO: enumerate failure reasons
675 */
676 nodename_buflen = sizeof(nodename_buf);
677 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY, "Server denied test: %s", I2AddrNodeName(cntrl->remote_addr, nodename_buf, &nodename_buflen));
678
679 *err_ret = OWPErrOK;
680 return 1;
681 }
682
683 /*
684 * Function: OWPSessionRequest
685 *
686 * Description:
687 * Public function used to request a test from the server.
688 *
689 * In Args:
690 *
691 * Out Args:
692 *
693 * Scope:
694 * Returns:
695 * True/False based upon acceptance from server. If False is returned
696 * check err_ret to see if an error condition exists. (If err_ret is
697 * not OWPErrOK, the control connection is probably no longer valid.)
698 * Side Effect:
699 */
700 OWPBoolean
OWPSessionRequest(OWPControl cntrl,I2Addr sender,OWPBoolean server_conf_sender,I2Addr receiver,OWPBoolean server_conf_receiver,OWPTestSpec * test_spec,FILE * fp,OWPSID sid_ret,OWPErrSeverity * err_ret)701 OWPSessionRequest(
702 OWPControl cntrl,
703 I2Addr sender,
704 OWPBoolean server_conf_sender,
705 I2Addr receiver,
706 OWPBoolean server_conf_receiver,
707 OWPTestSpec *test_spec,
708 FILE *fp,
709 OWPSID sid_ret,
710 OWPErrSeverity *err_ret
711 )
712 {
713 struct addrinfo *frai=NULL;
714 struct addrinfo *rai=NULL;
715 struct addrinfo *fsai=NULL;
716 struct addrinfo *sai=NULL;
717 OWPTestSession tsession = NULL;
718 int rc=0;
719 OWPAcceptType aval = OWP_CNTRL_ACCEPT;
720 struct sockaddr *rsaddr;
721 struct sockaddr *ssaddr;
722 socklen_t saddrlen;
723 int intr=1;
724 int *retn_on_intr=&intr;
725
726 *err_ret = OWPErrOK;
727
728 /*
729 * Check cntrl state is appropriate for this call.
730 * (this would happen as soon as we tried to call the protocol
731 * function - but it saves a lot of misplaced work to check now.)
732 */
733 if(!cntrl || !_OWPStateIsRequest(cntrl)){
734 *err_ret = OWPErrFATAL;
735 OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
736 "OWPSessionRequest: called with invalid cntrl record");
737 goto error;
738 }
739
740 /*
741 * Use application defined intr semantics if available.
742 * (Default is to fail on intrupted I/O.)
743 */
744 if(cntrl->retn_on_intr){
745 retn_on_intr = cntrl->retn_on_intr;
746 }
747
748 /*
749 * If NULL passed in for recv address - fill it in with local
750 */
751 if(!receiver){
752 if(server_conf_receiver){
753 OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
754 "OWPSessionRequest: called with invalid receiver address");
755 goto error;
756 }
757 else{
758 rsaddr = I2AddrSAddr(cntrl->local_addr,&saddrlen);
759 if( !(receiver = I2AddrBySAddr(OWPContextErrHandle(cntrl->ctx),
760 rsaddr,saddrlen,SOCK_DGRAM,IPPROTO_UDP))){
761 goto error;
762 }
763 }
764 }
765 if( !I2AddrSetSocktype(receiver,SOCK_DGRAM) ||
766 !I2AddrSetProtocol(receiver,IPPROTO_UDP) ||
767 !I2AddrSetPort(receiver,0)){
768 goto error;
769 }
770
771 /*
772 * If NULL passed in for send address - fill it in with local
773 */
774 if(!sender){
775 if(server_conf_sender){
776 OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
777 "OWPSessionRequest: called with invalid sender address");
778 goto error;
779 }
780 else{
781 ssaddr = I2AddrSAddr(cntrl->local_addr,&saddrlen);
782 if( !(sender = I2AddrBySAddr(OWPContextErrHandle(cntrl->ctx),
783 ssaddr,saddrlen,SOCK_DGRAM,IPPROTO_UDP))){
784 goto error;
785 }
786 }
787 }
788 if( !I2AddrSetSocktype(sender,SOCK_DGRAM) ||
789 !I2AddrSetProtocol(sender,IPPROTO_UDP) ||
790 !I2AddrSetPort(sender,0)){
791 goto error;
792 }
793
794 /*
795 * Get addrinfo for address spec's so we can choose between
796 * the different address possiblities in the next step.
797 */
798 if( !(frai = I2AddrAddrInfo(receiver,NULL,NULL)) ||
799 !(fsai = I2AddrAddrInfo(sender,NULL,NULL))){
800 goto error;
801 }
802
803 /*
804 * Determine proper address specifications for send/recv.
805 * Loop on ai values to find a match and use that.
806 * (We prefer IPV6 over others, so loop over IPv6 addrs first...)
807 * We only support AF_INET and AF_INET6.
808 */
809 if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv4Only)){
810 #ifdef AF_INET6
811 for(rai = frai;rai;rai = rai->ai_next){
812 if(rai->ai_family != AF_INET6) continue;
813 for(sai = fsai;sai;sai = sai->ai_next){
814 if(rai->ai_family != sai->ai_family) continue;
815 if(rai->ai_socktype != sai->ai_socktype) continue;
816 goto foundaddr;
817 }
818 }
819 #endif
820 }
821 if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv6Only)){
822 for(rai = frai;rai;rai = rai->ai_next){
823 if(rai->ai_family != AF_INET) continue;
824 for(sai = fsai;sai;sai = sai->ai_next){
825 if(rai->ai_family != sai->ai_family) continue;
826 if(rai->ai_socktype != sai->ai_socktype) continue;
827 goto foundaddr;
828 }
829 }
830 }
831
832 /*
833 * Didn't find compatible addrs - return error.
834 */
835 *err_ret = OWPErrWARNING;
836 OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
837 "OWPSessionRequest called with incompatible addresses");
838 goto error;
839
840 foundaddr:
841 /*
842 * Fill I2Addr records with "selected" addresses for test.
843 */
844 if( !I2AddrSetSAddr(receiver,rai->ai_addr,rai->ai_addrlen) ||
845 !I2AddrSetSAddr(sender,sai->ai_addr,sai->ai_addrlen)){
846
847 OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
848 "OWPSessionRequest: Unable to set socket information");
849 goto error;
850 }
851
852 /*
853 * Save direct pointers to the recv/send saddr's for later.
854 */
855 rsaddr = rai->ai_addr;
856 ssaddr = sai->ai_addr;
857 saddrlen = sai->ai_addrlen;
858
859 /*
860 * Create a structure to store the stuff we need to keep for
861 * later calls.
862 */
863 if( !(tsession = _OWPTestSessionAlloc(cntrl,sender,server_conf_sender,
864 receiver,server_conf_receiver,test_spec)))
865 goto error;
866
867 /*
868 * This section initializes the two endpoints for the test.
869 * EndpointInit is used to create a local socket and allocate
870 * a port for the local side of the test.
871 *
872 * EndpointInitHook is used to set the information for the
873 * remote side of the test and then the Endpoint process
874 * is forked off.
875 *
876 * The request to the server is interwoven in based upon which
877 * side needs to happen first. (The receiver needs to be initialized
878 * first because the SID comes from there - so, if conf_receiver
879 * then the request is sent to the server, and then other work
880 * happens. If the client is the receiver, then the local
881 * initialization needs to happen before sending the request.)
882 */
883
884 /*
885 * Configure receiver first since the sid comes from there.
886 */
887 if(server_conf_receiver){
888 /*
889 * If send local, check local policy for sender
890 */
891 if(!server_conf_sender){
892 /*
893 * create the local sender
894 */
895 if(!_OWPEndpointInit(cntrl,tsession,sender,NULL,
896 &aval,err_ret)){
897 goto error;
898 }
899 }
900 else{
901 /*
902 * This request will fail with the sample implementation
903 * owampd. owampd is not prepared to configure both
904 * endpoints - but let the test request go through
905 * here anyway. It will allow a client of the
906 * sample implementation to be used with a possibly
907 * more robust server.
908 */
909 ;
910 }
911
912 /*
913 * Request the server create the receiver & possibly the
914 * sender.
915 */
916 if((rc = _OWPClientRequestTestReadResponse(cntrl,retn_on_intr,
917 sender,server_conf_sender,
918 receiver,server_conf_receiver,
919 test_spec,tsession->sid,err_ret)) != 0){
920 goto error;
921 }
922
923 /*
924 * Now that we know the SID we can create the schedule
925 * context.
926 */
927 if(!(tsession->sctx = OWPScheduleContextCreate(cntrl->ctx,
928 tsession->sid,&tsession->test_spec))){
929 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
930 "Unable to init schedule generator");
931 goto error;
932 }
933
934 /*
935 * If sender is local, complete it's initialization now that
936 * we know the receiver port number.
937 */
938 if(!server_conf_sender){
939 /*
940 * check local policy for this sender
941 * (had to call policy check after initialize
942 * because schedule couldn't be computed until
943 * we got the SID from the server.)
944 */
945
946
947 if(!_OWPCallCheckTestPolicy(cntrl,True,
948 ssaddr,rsaddr,saddrlen,
949 test_spec,&tsession->closure,err_ret)){
950 OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
951 "Test not allowed");
952 goto error;
953 }
954
955 if(!_OWPEndpointInitHook(cntrl,tsession,&aval,err_ret)){
956 goto error;
957 }
958 }
959 }
960 else{
961 /*
962 * local receiver - create SID and compute schedule.
963 */
964 if(_OWPCreateSID(tsession) != 0){
965 goto error;
966 }
967
968 /*
969 * Now that we know the SID we can create the schedule
970 * context.
971 */
972 if(!(tsession->sctx = OWPScheduleContextCreate(cntrl->ctx,
973 tsession->sid,&tsession->test_spec))){
974 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
975 "Unable to init schedule generator");
976 goto error;
977 }
978
979 /*
980 * Local receiver - first check policy, then create.
981 */
982 if(!_OWPCallCheckTestPolicy(cntrl,False,
983 rsaddr,ssaddr,saddrlen,
984 test_spec,&tsession->closure,err_ret)){
985 OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
986 "Test not allowed");
987 goto error;
988 }
989 if(!_OWPEndpointInit(cntrl,tsession,receiver,fp,&aval,err_ret)){
990 goto error;
991 }
992
993
994 /*
995 * If conf_sender - make request to server
996 */
997 if(server_conf_sender){
998 if((rc = _OWPClientRequestTestReadResponse(cntrl,retn_on_intr,
999 sender,server_conf_sender,
1000 receiver,server_conf_receiver,
1001 test_spec,tsession->sid,err_ret)) != 0){
1002 goto error;
1003 }
1004 }
1005 else{
1006 /*
1007 * This is a VERY strange situation - the
1008 * client is setting up a test session without
1009 * making a request to the server...
1010 *
1011 * Just return an error here...
1012 */
1013 OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
1014 "Test not allowed");
1015 goto error;
1016 }
1017 if(!_OWPEndpointInitHook(cntrl,tsession,&aval,err_ret)){
1018 goto error;
1019 }
1020 }
1021
1022 /*
1023 * Server accepted our request, and we were able to initialize our
1024 * side of the test. Add this "session" to the tests list for this
1025 * control connection.
1026 */
1027 tsession->next = cntrl->tests;
1028 cntrl->tests = tsession;
1029
1030 /*
1031 * return the SID for this session to the caller.
1032 */
1033 memcpy(sid_ret,tsession->sid,sizeof(OWPSID));
1034
1035 return True;
1036
1037 error:
1038 switch(aval){
1039 case OWP_CNTRL_ACCEPT:
1040 break;
1041 case OWP_CNTRL_REJECT:
1042 OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,"Test not allowed");
1043 break;
1044 case OWP_CNTRL_UNSUPPORTED:
1045 OWPError(cntrl->ctx,*err_ret,OWPErrUNKNOWN,
1046 "Test type unsupported");
1047 break;
1048 case OWP_CNTRL_UNAVAILABLE_PERM:
1049 OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
1050 "Test denied: resources unavailable");
1051 break;
1052 case OWP_CNTRL_UNAVAILABLE_TEMP:
1053 OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
1054 "Test denied: resource temporarily unavailable");
1055 break;
1056 case OWP_CNTRL_FAILURE:
1057 default:
1058 OWPError(cntrl->ctx,*err_ret,OWPErrUNKNOWN,"Test failed");
1059 break;
1060 }
1061
1062 if(tsession){
1063 _OWPTestSessionFree(tsession,OWP_CNTRL_FAILURE);
1064 }
1065 else{
1066 /*
1067 * If tsession exists - the addr's will be free'd as part
1068 * of it - otherwise, do it here.
1069 */
1070 I2AddrFree(receiver);
1071 I2AddrFree(sender);
1072 }
1073
1074 return False;
1075 }
1076
1077 /*
1078 * Function: OWPStartSessions
1079 *
1080 * Description:
1081 * This function is used by applications to send the StartSessions
1082 * message to the server and to kick of it's side of all sessions.
1083 *
1084 * In Args:
1085 *
1086 * Out Args:
1087 *
1088 * Scope:
1089 * Returns:
1090 * Side Effect:
1091 */
1092 OWPErrSeverity
OWPStartSessions(OWPControl cntrl)1093 OWPStartSessions(
1094 OWPControl cntrl
1095 )
1096 {
1097 int rc;
1098 OWPErrSeverity err,err2=OWPErrOK;
1099 OWPTestSession tsession;
1100 OWPAcceptType acceptval;
1101 int intr=1;
1102 int *retn_on_intr=&intr;
1103
1104 /*
1105 * Must pass valid cntrl record.
1106 */
1107 if(!cntrl){
1108 OWPError(NULL,OWPErrFATAL,OWPErrINVALID,
1109 "OWPStartSessions called with invalid cntrl record");
1110 return OWPErrFATAL;
1111 }
1112
1113 /*
1114 * Use application defined intrrupt semantics if avail.
1115 * (Default is to fail on intrrupted I/O.)
1116 */
1117 if(cntrl->retn_on_intr){
1118 retn_on_intr = cntrl->retn_on_intr;
1119 }
1120
1121 /*
1122 * Send the StartSessions message to the server
1123 */
1124 if((rc = _OWPWriteStartSessions(cntrl,retn_on_intr)) < OWPErrOK){
1125 return _OWPFailControlSession(cntrl,rc);
1126 }
1127
1128 /*
1129 * Small optimization... - start local receivers while waiting for
1130 * the server to respond. (should not start senders - don't want
1131 * to send packets unless control-ack comes back positive.)
1132 */
1133 for(tsession = cntrl->tests;tsession;tsession = tsession->next){
1134 if(tsession->endpoint && !tsession->endpoint->send){
1135 if(!_OWPEndpointStart(tsession->endpoint,&err)){
1136 return _OWPFailControlSession(cntrl,err);
1137 }
1138 err2 = MIN(err,err2);
1139 }
1140 }
1141
1142 /*
1143 * Read the server response.
1144 */
1145 if(((rc = _OWPReadStartAck(cntrl,retn_on_intr,&acceptval)) < OWPErrOK) ||
1146 (acceptval != OWP_CNTRL_ACCEPT)){
1147 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1148 }
1149
1150 /*
1151 * Now start local senders.
1152 */
1153 for(tsession = cntrl->tests;tsession;tsession = tsession->next){
1154 if(tsession->endpoint && tsession->endpoint->send){
1155 if(!_OWPEndpointStart(tsession->endpoint,&err)){
1156 return _OWPFailControlSession(cntrl,err);
1157 }
1158 err2 = MIN(err,err2);
1159 }
1160 }
1161
1162 return err2;
1163 }
1164
1165 /*
1166 * Function: OWPDelay
1167 *
1168 * Description:
1169 * Compute delay between two timestamps.
1170 *
1171 * In Args:
1172 *
1173 * Out Args:
1174 *
1175 * Scope:
1176 * Returns:
1177 * Side Effect:
1178 */
1179 double
OWPDelay(OWPTimeStamp * send_time,OWPTimeStamp * recv_time)1180 OWPDelay(
1181 OWPTimeStamp *send_time,
1182 OWPTimeStamp *recv_time
1183 )
1184 {
1185 return OWPNum64ToDouble(recv_time->owptime) -
1186 OWPNum64ToDouble(send_time->owptime);
1187 }
1188
1189 /*
1190 * Function: OWPFetchSession
1191 *
1192 * Description:
1193 * This function is used to request that the data for the TestSession
1194 * identified by sid be fetched from the server and copied to the
1195 * file pointed at by fp. This function assumes fp is currently pointing
1196 * at an open file, and that fp is ready to write at the begining of the
1197 * file.
1198 *
1199 * To request an entire session set begin = 0, and end = 0xFFFFFFFF.
1200 * (This is only valid if the session is complete - otherwise the server
1201 * should deny this request.)
1202 * Otherwise, "begin" and "end" refer to sequence numbers in the test
1203 * session.
1204 * The number of records returned will not necessarily be end-begin due
1205 * to possible loss and/or duplication.
1206 *
1207 * There is a full description of the owp file format in the comments
1208 * in api.c.
1209 *
1210 * In Args:
1211 *
1212 * Out Args:
1213 *
1214 * Scope:
1215 * Returns:
1216 * The number of data records in the file. If < 1, check err_ret to
1217 * find out if it was an error condition: ErrOK just means the request
1218 * was denied by the server. ErrWARNING means there was a local
1219 * problem (fp not writeable etc...) and the control connection is
1220 * still valid.
1221 * Side Effect:
1222 */
1223 uint32_t
OWPFetchSession(OWPControl cntrl,FILE * fp,uint32_t begin,uint32_t end,OWPSID sid,OWPErrSeverity * err_ret)1224 OWPFetchSession(
1225 OWPControl cntrl,
1226 FILE *fp,
1227 uint32_t begin,
1228 uint32_t end,
1229 OWPSID sid,
1230 OWPErrSeverity *err_ret
1231 )
1232 {
1233 OWPAcceptType acceptval;
1234 uint8_t finished;
1235 uint32_t n;
1236 OWPTestSession tsession = NULL;
1237 OWPSessionHeaderRec hdr;
1238 off_t toff;
1239 char buf[_OWP_FETCH_BUFFSIZE];
1240 OWPBoolean dowrite = True;
1241 struct sockaddr *saddr;
1242 socklen_t saddrlen;
1243 int intr=1;
1244 int *retn_on_intr=&intr;
1245
1246 *err_ret = OWPErrOK;
1247
1248 if(!fp){
1249 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1250 "OWPFetchSession: Invalid fp");
1251 *err_ret = OWPErrFATAL;
1252 return 0;
1253 }
1254
1255 /*
1256 * Use application defined intrrupt semantics if avail.
1257 * (Default is to fail on intrrupted I/O.)
1258 */
1259 if(cntrl->retn_on_intr){
1260 retn_on_intr = cntrl->retn_on_intr;
1261 }
1262
1263 /*
1264 * Initialize file header record.
1265 */
1266 memset(&hdr,0,sizeof(hdr));
1267
1268 /*
1269 * Make the request of the server.
1270 */
1271 if((*err_ret = _OWPWriteFetchSession(cntrl,retn_on_intr,
1272 begin,end,sid)) < OWPErrWARNING){
1273 goto failure;
1274 }
1275
1276 /*
1277 * Read the response
1278 */
1279 if((*err_ret = _OWPReadFetchAck(cntrl,retn_on_intr,
1280 &acceptval,&finished,&hdr.next_seqno,
1281 &hdr.num_skiprecs,&hdr.num_datarecs)) < OWPErrWARNING){
1282 goto failure;
1283 }
1284 /* store 8 bit finished in 32 bit hdr.finished field. */
1285 hdr.finished = finished;
1286
1287 /*
1288 * If the server didn't accept, the fetch response is complete.
1289 */
1290 if(acceptval != OWP_CNTRL_ACCEPT){
1291 return 0;
1292 }
1293
1294 /*
1295 * Representation of original TestReq is first.
1296 */
1297 if((*err_ret = _OWPReadTestRequest(cntrl,retn_on_intr,
1298 &tsession,NULL)) != OWPErrOK){
1299 goto failure;
1300 }
1301
1302 /*
1303 * Write the file header now. First encode the tsession into
1304 * a SessionHeader.
1305 */
1306 if( !(saddr = I2AddrSAddr(tsession->sender,&saddrlen))){
1307 goto failure;
1308 }
1309 assert(sizeof(hdr.addr_sender) >= saddrlen);
1310 memcpy(&hdr.addr_sender,saddr,saddrlen);
1311
1312 if( !(saddr = I2AddrSAddr(tsession->receiver,&saddrlen))){
1313 goto failure;
1314 }
1315 assert(sizeof(hdr.addr_receiver) >= saddrlen);
1316 memcpy(&hdr.addr_receiver,saddr,saddrlen);
1317
1318 hdr.conf_sender = tsession->conf_sender;
1319 hdr.conf_receiver = tsession->conf_receiver;
1320
1321 memcpy(hdr.sid,tsession->sid,sizeof(hdr.sid));
1322 /* hdr.test_spec will now point at same slots memory. */
1323 hdr.test_spec = tsession->test_spec;
1324
1325 /*
1326 * Now, actually write the header
1327 */
1328 if( !OWPWriteDataHeader(cntrl->ctx,fp,&hdr)){
1329 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1330 "OWPFetchSession: OWPWriteDataHeader(): %M");
1331 *err_ret = OWPErrWARNING;
1332 dowrite = False;
1333 }
1334
1335 /*
1336 * Done with tsession
1337 * (Make sure hdr.test_spec->slots is not accessed - mem is freed!)
1338 */
1339 (void)_OWPTestSessionFree(tsession,OWP_CNTRL_INVALID);
1340 hdr.test_spec.slots = NULL;
1341
1342 /*
1343 * Skip records:
1344 *
1345 * How many octets of skip records?
1346 */
1347 toff = hdr.num_skiprecs * _OWP_SKIPREC_SIZE;
1348
1349 /*
1350 * Read even AES blocks of skips first
1351 */
1352 while(toff > _OWP_RIJNDAEL_BLOCK_SIZE){
1353 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1354 *err_ret = OWPErrFATAL;
1355 goto failure;
1356 }
1357 _OWPRecvHMACAdd(cntrl,buf,1);
1358 if(dowrite && ( fwrite(buf,1,_OWP_RIJNDAEL_BLOCK_SIZE,fp) !=
1359 _OWP_RIJNDAEL_BLOCK_SIZE)){
1360 OWPError(cntrl->ctx,OWPErrFATAL,errno,
1361 "OWPFetchSession: fwrite(): %M");
1362 dowrite = False;
1363 }
1364 toff -= _OWP_RIJNDAEL_BLOCK_SIZE;
1365 }
1366 /*
1367 * Finish incomplete block
1368 */
1369 if(toff){
1370 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1371 *err_ret = OWPErrFATAL;
1372 goto failure;
1373 }
1374 _OWPRecvHMACAdd(cntrl,buf,1);
1375 if(dowrite && ( fwrite(buf,1,toff,fp) != (size_t)toff)){
1376 OWPError(cntrl->ctx,OWPErrFATAL,errno,
1377 "OWPFetchSession: fwrite(): %M");
1378 dowrite = False;
1379 }
1380 }
1381
1382 /*
1383 * Read sent HMAC digest and compare
1384 */
1385 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1386 *err_ret = OWPErrFATAL;
1387 goto failure;
1388 }
1389 if(!_OWPRecvHMACCheckClear(cntrl,buf)){
1390 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1391 "OWPFetchSession: Invalid HMAC");
1392 *err_ret = OWPErrFATAL;
1393 goto failure;
1394 }
1395
1396 /*
1397 * Data records are next (fp is already positioned correctly).
1398 */
1399
1400 for(n=hdr.num_datarecs;
1401 n >= _OWP_FETCH_DATAREC_BLOCKS;
1402 n -= _OWP_FETCH_DATAREC_BLOCKS){
1403 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,_OWP_FETCH_AES_BLOCKS,
1404 retn_on_intr) != _OWP_FETCH_AES_BLOCKS){
1405 *err_ret = OWPErrFATAL;
1406 goto failure;
1407 }
1408 _OWPRecvHMACAdd(cntrl,buf,_OWP_FETCH_AES_BLOCKS);
1409 if(dowrite && (fwrite(buf,_OWP_DATAREC_SIZE,
1410 _OWP_FETCH_DATAREC_BLOCKS,fp) !=
1411 _OWP_FETCH_DATAREC_BLOCKS)){
1412 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1413 "OWPFetchSession: fwrite(): %M");
1414 dowrite = False;
1415 }
1416 }
1417
1418 if(n){
1419 /*
1420 * Read enough AES blocks to get remaining records.
1421 */
1422 int blks = n*_OWP_DATAREC_SIZE/_OWP_RIJNDAEL_BLOCK_SIZE + 1;
1423
1424 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,
1425 blks,retn_on_intr) != blks){
1426 *err_ret = OWPErrFATAL;
1427 goto failure;
1428 }
1429 _OWPRecvHMACAdd(cntrl,buf,blks);
1430 if(dowrite && (fwrite(buf,_OWP_DATAREC_SIZE,n,fp) != n)){
1431 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1432 "OWPFetchSession: fwrite(): %M");
1433 dowrite = False;
1434 }
1435 }
1436
1437 fflush(fp);
1438
1439 /*
1440 * Read final block of HMAC
1441 */
1442 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1443 *err_ret = OWPErrFATAL;
1444 goto failure;
1445 }
1446 if(!_OWPRecvHMACCheckClear(cntrl,buf)){
1447 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1448 "OWPFetchSession: Invalid HMAC");
1449 *err_ret = OWPErrFATAL;
1450 goto failure;
1451 }
1452
1453 /*
1454 * reset state to request.
1455 */
1456 cntrl->state &= ~_OWPStateFetching;
1457 cntrl->state |= _OWPStateRequest;
1458
1459 if(!dowrite){
1460 *err_ret = OWPErrWARNING;
1461 hdr.num_datarecs = 0;
1462 }
1463
1464 return hdr.num_datarecs;
1465
1466 failure:
1467 (void)_OWPFailControlSession(cntrl,*err_ret);
1468 return 0;
1469 }
1470
1471 /*
1472 * Function: OWPParsePortRange
1473 *
1474 * Description:
1475 * Fills in the passed OWPPortRangeRec with the values from the passed
1476 * in port range string. A valid port range string consists of either
1477 * "0", a specific port or a range like "min-max". It returns False on
1478 * failure and True on success. If failure is returned, the contents of
1479 * the OWPPortRangeRec are unspecified.
1480 *
1481 * In Args:
1482 *
1483 * Out Args:
1484 *
1485 * Scope:
1486 * Returns:
1487 * Side Effect:
1488 */
1489 I2Boolean
OWPParsePortRange(char * pspec,OWPPortRangeRec * portspec)1490 OWPParsePortRange (
1491 char *pspec,
1492 OWPPortRangeRec *portspec
1493 )
1494 {
1495 char *tstr,*endptr;
1496 long tint;
1497
1498 if(!pspec) return False;
1499
1500 tstr = pspec;
1501 endptr = NULL;
1502
1503 while(isspace((int)*tstr)) tstr++;
1504 tint = strtol(tstr,&endptr,10);
1505 if(!endptr || (tstr == endptr) || (tint < 0) || (tint > (int)0xffff)){
1506 goto failed;
1507 }
1508 portspec->low = (uint16_t)tint;
1509
1510 while(isspace((int)*endptr)) endptr++;
1511
1512 switch(*endptr){
1513 case '\0':
1514 /* only allow a single value if it is 0 */
1515 if(!portspec->low){
1516 goto failed;
1517 }
1518 portspec->high = portspec->low;
1519 goto done;
1520 break;
1521 case '-':
1522 endptr++;
1523 break;
1524 default:
1525 goto failed;
1526 }
1527
1528 tstr = endptr;
1529 endptr = NULL;
1530 while(isspace((int)*tstr)) tstr++;
1531 tint = strtol(tstr,&endptr,10);
1532 if(!endptr || (tstr == endptr) || (tint < 0) || (tint > (int)0xffff)){
1533 goto failed;
1534 }
1535 portspec->high = (uint16_t)tint;
1536
1537 if(portspec->high < portspec->low){
1538 goto failed;
1539 }
1540
1541 done:
1542 /*
1543 * If ephemeral is specified, shortcut by not setting.
1544 */
1545 if(!portspec->high && !portspec->low)
1546 return True;
1547
1548 return True;
1549
1550 failed:
1551 return False;
1552 }
1553