summaryrefslogtreecommitdiff
path: root/lib/ZSendPkt.c
blob: fccf7fe8b02b2f709b764f6bc64f795ff0096eb9 (plain)
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
/* This file is part of the Project Athena Zephyr Notification System.
 * It contains source for the ZSendPacket function.
 *
 *	Created by:	Robert French
 *
 *	$Source$
 *	$Author$
 *
 *	Copyright (c) 1987 by the Massachusetts Institute of Technology.
 *	For copying and distribution information, see the file
 *	"mit-copyright.h". 
 */
/* $Header$ */

#ifndef lint
static char rcsid_ZSendPacket_c[] = "$Header$";
#endif lint

#include <zephyr/mit-copyright.h>

#include <zephyr/zephyr_internal.h>
#include <sys/socket.h>
#ifdef _AIX
#include <sys/select.h>
#endif

Code_t ZSendPacket(packet, len, waitforack)
    char *packet;
    int len;
    int waitforack;
{
    int wait_for_hmack();
    Code_t retval;
    struct sockaddr_in dest;
    struct timeval tv, t0;
    fd_set zfdmask;
    int i, zfd;
    ZNotice_t notice, acknotice;
	
    if (!packet || len < 0)
	return (ZERR_ILLVAL);

    if (len > Z_MAXPKTLEN)
	return (ZERR_PKTLEN);
    
    if (ZGetFD() < 0)
	if ((retval = ZOpenPort((u_short *)0)) != ZERR_NONE)
	    return (retval);

    dest = ZGetDestAddr();
	
    if (sendto(ZGetFD(), packet, len, 0, (struct sockaddr *)&dest,
	       sizeof(dest)) < 0)
	return (errno);

    if (!waitforack)
	return (ZERR_NONE);

    if ((retval = ZParseNotice(packet, len, &notice)) != ZERR_NONE)
	return (retval);
    
    tv.tv_sec = HM_TIMEOUT;
    tv.tv_usec = 0;
    /* It is documented in select(2) that future versions of select
       will adjust the passed timeout to indicate the time remaining.
       When this is done, the variable t0 and all references to it
       can be removed.  */
    gettimeofday(&t0, 0);
    FD_ZERO(&zfdmask);
    zfd = ZGetFD();
    FD_SET(zfd, &zfdmask);
    while(1) {
      i = select(zfd + 1, &zfdmask, (fd_set *) 0, (fd_set *) 0, &tv);
      if(i > 0) {
	retval = ZCheckIfNotice(&acknotice, (struct sockaddr_in *)0,
				wait_for_hmack, (char *)&notice.z_uid);
	if (retval == ZERR_NONE) {
	  ZFreeNotice(&acknotice);
	  return (ZERR_NONE);
	}
	if (retval != ZERR_NONOTICE)
	  return (retval);
      } else if(i == 0) {	/* time out */
	return ZERR_HMDEAD;
      } else if(i < 0 && errno != EINTR) {
	return errno;
      }
      /* Here to end of loop deleted if/when select modifies passed timeout */
      gettimeofday(&tv, 0);
      tv.tv_usec = tv.tv_usec - t0.tv_usec;
      if(tv.tv_usec < 0)
	{
	  tv.tv_usec += 1000000;
	  tv.tv_sec = HM_TIMEOUT - 1 + tv.tv_sec - t0.tv_sec;
	} else {
	  tv.tv_sec = HM_TIMEOUT + tv.tv_sec - t0.tv_sec;
	}
    }
}

static int wait_for_hmack(notice, uid)
    ZNotice_t *notice;
    ZUnique_Id_t *uid;
{
    return (notice->z_kind == HMACK && ZCompareUID(&notice->z_uid, uid));
}