123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- /*
- * The MySensors Arduino library handles the wireless radio link and protocol
- * between your home built sensors/actuators and HA controller of choice.
- * The sensors forms a self healing radio network with optional repeaters. Each
- * repeater and gateway builds a routing tables in EEPROM which keeps track of the
- * network topology allowing messages to be routed to nodes.
- *
- * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
- * Copyright (C) 2013-2018 Sensnology AB
- * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
- *
- * Documentation: http://www.mysensors.org
- * Support Forum: http://forum.mysensors.org
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
- */
-
- #include "EthernetServer.h"
- #include <cstdio>
- #include <sys/socket.h>
- #include <cstring>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <errno.h>
- #include <fcntl.h>
- #include "log.h"
- #include "EthernetClient.h"
-
- EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port),
- max_clients(max_clients), sockfd(-1)
- {
- clients.reserve(max_clients);
- }
-
- void EthernetServer::begin()
- {
- begin(IPAddress(0,0,0,0));
- }
-
- void EthernetServer::begin(IPAddress address)
- {
- struct addrinfo hints, *servinfo, *p;
- int yes=1;
- int rv;
- char ipstr[INET_ADDRSTRLEN];
- char portstr[6];
-
- if (sockfd != -1) {
- close(sockfd);
- sockfd = -1;
- }
-
- memset(&hints, 0, sizeof hints);
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
-
- sprintf(portstr, "%d", port);
- if ((rv = getaddrinfo(address.toString().c_str(), portstr, &hints, &servinfo)) != 0) {
- logError("getaddrinfo: %s\n", gai_strerror(rv));
- return;
- }
-
- // loop through all the results and bind to the first we can
- for (p = servinfo; p != NULL; p = p->ai_next) {
- if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
- logError("socket: %s\n", strerror(errno));
- continue;
- }
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
- logError("setsockopt: %s\n", strerror(errno));
- freeaddrinfo(servinfo);
- return;
- }
-
- if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
- close(sockfd);
- logError("bind: %s\n", strerror(errno));
- continue;
- }
-
- break;
- }
-
- if (p == NULL) {
- logError("Failed to bind!\n");
- freeaddrinfo(servinfo);
- return;
- }
-
- if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) {
- logError("listen: %s\n", strerror(errno));
- freeaddrinfo(servinfo);
- return;
- }
-
- freeaddrinfo(servinfo);
-
- fcntl(sockfd, F_SETFL, O_NONBLOCK);
-
- struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
- void *addr = &(ipv4->sin_addr);
- inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
- logDebug("Listening for connections on %s:%s\n", ipstr, portstr);
- }
-
- bool EthernetServer::hasClient()
- {
- // Check if any client has disconnected
- for (size_t i = 0; i < clients.size(); ++i) {
- EthernetClient client(clients[i]);
- if (!client.connected()) {
- // Checks if this disconnected client is also on the new clients list
- for (std::list<int>::iterator it = new_clients.begin(); it != new_clients.end(); ++it) {
- if (*it == clients[i]) {
- new_clients.erase(it);
- break;
- }
- }
- client.stop();
- clients[i] = clients.back();
- clients.pop_back();
- logDebug("Ethernet client disconnected.\n");
- }
- }
-
- _accept();
-
- return !new_clients.empty();
- }
-
- EthernetClient EthernetServer::available()
- {
- if (new_clients.empty()) {
- return EthernetClient();
- } else {
- int sock = new_clients.front();
- new_clients.pop_front();
- return EthernetClient(sock);
- }
- }
-
- size_t EthernetServer::write(uint8_t b)
- {
- return write(&b, 1);
- }
-
- size_t EthernetServer::write(const uint8_t *buffer, size_t size)
- {
- size_t n = 0;
-
- for (size_t i = 0; i < clients.size(); ++i) {
- EthernetClient client(clients[i]);
- if (client.status() == ETHERNETCLIENT_W5100_ESTABLISHED) {
- n += client.write(buffer, size);
- }
- }
-
- return n;
- }
-
- size_t EthernetServer::write(const char *str)
- {
- if (str == NULL) {
- return 0;
- }
- return write((const uint8_t *)str, strlen(str));
- }
-
- size_t EthernetServer::write(const char *buffer, size_t size)
- {
- return write((const uint8_t *)buffer, size);
- }
-
- void EthernetServer::_accept()
- {
- int new_fd;
- socklen_t sin_size;
- struct sockaddr_storage client_addr;
- char ipstr[INET_ADDRSTRLEN];
-
- sin_size = sizeof client_addr;
- new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
- if (new_fd == -1) {
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- logError("accept: %s\n", strerror(errno));
- }
- return;
- }
-
- if (clients.size() == max_clients) {
- // no free slots, search for a dead client
- close(new_fd);
- logDebug("Max number of ethernet clients reached.\n");
- return;
- }
-
- new_clients.push_back(new_fd);
- clients.push_back(new_fd);
-
- void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr);
- inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr);
- logDebug("New connection from %s\n", ipstr);
- }
|