1// LSHOSTS.C
2
3// BeOS-specific includes
4#include "TypeConstants.h"
5#include "Errors.h"
6#include "OS.h"
7
8// POSIX includes
9#include "stdio.h"
10#include "malloc.h"
11#include "string.h"
12#include "errno.h"
13#include "socket.h"
14#include "netdb.h"
15#include "signal.h"
16
17#include "betalk.h"
18#include "sysdepdefs.h"
19
20#ifndef NULL
21#define NULL			0L
22#endif
23
24#ifndef INVALID_SOCKET
25#define INVALID_SOCKET		(int)(~0)
26#endif
27
28int main(int argc, char *argv[]);
29static void recvAlarm(int signal);
30static void usage();
31
32
33int main(int argc, char *argv[])
34{
35	bt_request request;
36	struct sockaddr_in ourAddr, toAddr, fromAddr;
37	struct hostent *ent;
38	char buffer[8192];
39	int sock, addrLen, bytes;
40	unsigned int serverIP;
41#ifdef SO_BROADCAST
42	int on = 1;
43#endif
44
45	if (argc > 2)
46		usage();
47
48	memset(&toAddr, 0, sizeof(toAddr));
49	toAddr.sin_family = AF_INET;
50	toAddr.sin_port = htons(BT_QUERYHOST_PORT);
51	if (argc == 1)
52		toAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
53	else
54	{
55		ent = gethostbyname(argv[1]);
56		if (ent == NULL)
57			return 0;
58
59		serverIP = ntohl(*((unsigned int *) ent->h_addr));
60		toAddr.sin_addr.s_addr = htonl(serverIP);
61	}
62
63	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
64	if (sock == INVALID_SOCKET)
65		return 0;
66
67	memset(&ourAddr, 0, sizeof(ourAddr));
68	ourAddr.sin_family = AF_INET;
69	ourAddr.sin_port = htons(BT_QUERYHOST_PORT);
70	ourAddr.sin_addr.s_addr = htonl(INADDR_ANY);
71
72	if (bind(sock, (struct sockaddr *) &ourAddr, sizeof(ourAddr)))
73		if (errno != EADDRINUSE)
74			return 0;
75
76	// Normally, a setsockopt() call is necessary to turn broadcast mode on
77	// explicitly, although some versions of Unix don't care.  BeOS doesn't
78	// currently even define SO_BROADCAST, unless you have BONE installed.
79#ifdef SO_BROADCAST
80	if (argc == 1)
81		if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
82		{
83			printf("Unable to obtain permission for a network broadcast.\n");
84			closesocket(sock);
85			return 0;
86		}
87#endif
88	signal(SIGALRM, recvAlarm);
89
90	strcpy(request.signature, BT_RPC_SIGNATURE);
91	request.command = (argc == 1) ? BT_REQ_HOST_PROBE : BT_REQ_SHARE_PROBE;
92	if (sendto(sock, (char *) &request, sizeof(request), 0, (struct sockaddr *) &toAddr, sizeof(toAddr)) == -1)
93	{
94		printf("%s\n", strerror(errno));
95		closesocket(sock);
96		return 0;
97	}
98
99	memset(buffer, 0, sizeof(buffer));
100	alarm(3);
101
102	while (1)
103	{
104		addrLen = sizeof(fromAddr);
105		bytes = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *) &fromAddr, &addrLen);
106		if (bytes < 0)
107		{
108			if (errno == EINTR)
109				break;
110		}
111
112		if (strncmp(buffer, BT_RPC_SIGNATURE, strlen(BT_RPC_SIGNATURE)) != 0)
113			if (argc == 1)
114			{
115				struct sockaddr_in *sin = (struct sockaddr_in *) &fromAddr;
116				ent = gethostbyaddr((char *) &sin->sin_addr, sizeof(sin->sin_addr), AF_INET);
117				if (ent)
118					printf("%s\n", ent->h_name);
119				else
120				{
121					uint8 *p = (uint8 *) &sin->sin_addr;
122					printf("%d.%d.%d.%d\n", p[0], p[1], p[2], p[3]);
123				}
124			}
125			else
126			{
127				bt_resource resource;
128				int bufPos = 0;
129				while (bufPos < bytes)
130				{
131					memcpy(&resource, buffer + bufPos, sizeof(bt_resource));
132					resource.type = B_LENDIAN_TO_HOST_INT32(resource.type);
133					resource.subType = B_LENDIAN_TO_HOST_INT32(resource.subType);
134					if (resource.type == BT_SHARED_NULL)
135						break;
136
137					bufPos += sizeof(bt_resource);
138					printf("%s (%s)\n", resource.name,
139						resource.type == BT_SHARED_FOLDER ? "Shared Files" : "Shared Printer");
140				}
141			}
142	}
143
144	alarm(0);
145	signal(SIGALRM, SIG_DFL);
146	closesocket(sock);
147}
148
149static void recvAlarm(int signal)
150{
151	return;
152}
153
154static void usage()
155{
156	printf("Usage: lshosts [host]\n");
157	exit(0);
158}
159