Skip to content

Instantly share code, notes, and snippets.

@jfmherokiller
Last active July 12, 2024 23:26
Show Gist options
  • Save jfmherokiller/53279e9251b5dd0c463ec8028df7192e to your computer and use it in GitHub Desktop.
Save jfmherokiller/53279e9251b5dd0c463ec8028df7192e to your computer and use it in GitHub Desktop.
towel.blinkenlights.nl switch example
Usage:
put the telnet.nro and telnet.conf files in the /switch folder
cmake_minimum_required(VERSION 3.5)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
add_executable(stelenet stelnet.c)
target_link_libraries(stelenet -lnx )
/*
SimpleTelnet: a simple telnet client suitable for embedded systems
Copyright (C) 2013 [email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
//#include <termios.h>
#include <fcntl.h>
#include <switch.h>
#include <netdb.h>
#include <limits.h>
#define DO 0xfd
#define WONT 0xfc
#define WILL 0xfb
//#define DONT 0xfe
#define CMD 0xff
//#define CMD_ECHO 1
#define CMD_WINDOW_SIZE 31
char ServerIP[255];
char ServerPort[255];
int sock;
void ExitProgram() {
close(sock);
gfxExit();
socketExit();
}
void ReadConfigFile(char *ConfigFileName) {
FILE *configfile = fopen(ConfigFileName, "r");
if (configfile == NULL) perror("Error opening file");
//GetServerIP
fgets(ServerIP, 255, configfile);
//GetServerPort
fgets(ServerPort, 255, configfile);
//remove the newline chars
strtok(ServerIP, "\n\r");
strtok(ServerPort, "\n\r");
fclose(configfile);
}
//Get Ip of the host and write it to the server
void GetHostIp(char *name, struct sockaddr_in *in) {
struct hostent *he;
struct in_addr **addr_list;
// get the host info
if ((he = gethostbyname(name)) == NULL) {
herror("gethostbyname");
sleep(5);
exit(0);
} else {
// print information about this host:
printf("Official name is: %s\n", he->h_name);
printf(" IP addresses: ");
addr_list = (struct in_addr **) he->h_addr_list;
for (int i = 0; addr_list[i] != NULL; i++) {
printf("%s ", inet_ntoa(*addr_list[i]));
}
printf("\n");
memcpy(&(in->sin_addr), he->h_addr_list[0], (size_t) he->h_length);
}
freehostent(he);
}
void negotiate(int sock, unsigned char *buf, size_t len) {
if (buf[1] == DO && buf[2] == CMD_WINDOW_SIZE) {
unsigned char tmp1[10] = {255, 251, 31};
if (send(sock, tmp1, 3, 0) < 0)
exit(1);
unsigned char tmp2[10] = {255, 250, 31, 0, 80, 0, 24, 255, 240};
if (send(sock, tmp2, 9, 0) < 0)
exit(1);
return;
}
for (int i = 0; i < len; i++) {
if (buf[i] == DO)
buf[i] = WONT;
else if (buf[i] == WILL)
buf[i] = DO;
}
if (send(sock, buf, len, 0) < 0)
exit(1);
}
#define BUFLEN 20
int main(int argc, char *argv[]) {
atexit(ExitProgram);
gfxInitDefault();
//Initialize console. Using NULL as the second argument tells the console library to use the internal console structure as current one.
consoleInit(NULL);
socketInitializeDefault();
ReadConfigFile("/switch/telnet.conf");
struct sockaddr_in server;
bzero(&server, sizeof(server));
unsigned char buf[BUFLEN + 1];
ssize_t len;
//Create socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("Could not create socket. Error");
return 0;
}
//setup server struct with needed addtesss and resolve host
server.sin_family = AF_INET;
server.sin_port = htons((uint16_t) atoi(ServerPort));
GetHostIp(ServerIP, &server);
//Connect to remote server
if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("connect failed. Error");
return 0;
}
puts("Connected...\n");
// set terminal
//terminal_set();
//atexit(terminal_reset);
struct timeval ts;
ts.tv_sec = 1; // 1 second
ts.tv_usec = 0;
// select setup
fd_set fds;
FD_ZERO(&fds);
if (sock != 0) {
FD_SET(sock, &fds);
}
//FD_SET(0, &fds);
while (appletMainLoop()) {
hidScanInput();
// wait for data
int nready = select(sock + 1, &fds, 0, 0, &ts);
if (nready < 0) {
perror("select. Error");
break;
} else if (nready == 0) {
ts.tv_sec = 1; // 1 second
ts.tv_usec = 0;
} else if (sock != 0 && FD_ISSET(sock, &fds)) {
// start by reading a single byte
ssize_t rv;
if ((rv = recv(sock, buf, 1, 0)) < 0)
break;
else if (rv == 0) {
printf("Connection closed by the remote end\n\r");
break;
}
if (buf[0] == CMD) {
// read 2 more bytes
len = recv(sock, buf + 1, 2, 0);
if (len < 0)
break;
else if (len == 0) {
printf("Connection closed by the remote end\n\r");
break;
}
negotiate(sock, buf, 3);
} else {
len = 1;
buf[len] = '\0';
printf("%s", buf);
fflush(0);
}
//Send Disabled because there is no way to send text input yet
} /*else if (FD_ISSET(0, &fds)) {
buf[0] = getc(stdin); //fgets(buf, 1, stdin);
if (send(sock, buf, 1, 0) < 0)
break;
if (buf[0] == '\n') // with the terminal in raw mode we need to force a LF
putchar('\r');
}*/
//hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame)
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (kDown & KEY_PLUS) break; // break in order to return to hbmenu
gfxFlushBuffers();
gfxSwapBuffers();
gfxWaitForVsync();
}
return 0;
}
set(DEVKITPRO "/opt/devkitpro")
set(NX 1)
set(CMAKE_SYSTEM_NAME "Generic")
set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc")
set(CMAKE_CXX_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++")
set(CMAKE_AR "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ar" CACHE STRING "")
set(CMAKE_RANLIB "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ranlib" CACHE STRING "")
set(PKG_CONFIG "${DEVKITPRO}/portlibs/bin/aarch64-none-elf-pkg-config" CACHE STRING "")
set(CPPFLAGS "-D__SWITCH__ -I${DEVKITPRO}/libnx/include -I${DEVKITPRO}/portlibs/switch/include")
set(CMAKE_C_FLAGS "${CPPFLAGS} -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIC -ffunction-sections" CACHE STRING "C flags")
set(CMAKE_CXX_FLAGS "${CPPFLAGS} ${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -std=gnu++11" CACHE STRING "C++ flags")
set(CMAKE_FIND_ROOT_PATH ${DEVKITPRO}/devkitA64 ${DEVKITPRO}/libnx ${DEVKITPRO}/portlibs/switch)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
#set(CMAKE_STATIC_LINKER_FLAGS_INIT "-march=armv8-a -mtune=cortex-a57 -mtp=soft -L${DEVKITPRO}/libnx/lib -L${DEVKITPRO}/portlibs/switch/lib")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-specs=${DEVKITPRO}/libnx/switch.specs -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -L${DEVKITPRO}/libnx/lib -L${DEVKITPRO}/portlibs/switch/lib")
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available")
set(CMAKE_INSTALL_PREFIX ${DEVKITPRO}/portlibs/switch)
towel.blinkenlights.nl
23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment