first commit, unfinished wip
This commit is contained in:
44
Makefile
Normal file
44
Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
CC := clang
|
||||
CFLAGS := -I include -Wall -Wextra
|
||||
CFLAGS_DBG := $(CFLAGS) -g -O0
|
||||
CFLAGS_REL := $(CFLAGS) -O2
|
||||
|
||||
LDFLAGS :=
|
||||
LDFLAGS_REL := $(LDFLAGS) -s
|
||||
|
||||
BUILD_DIR := build
|
||||
SRC_DIR := src
|
||||
INCLUDE_DIR := include
|
||||
|
||||
APPLICATION := bbirc
|
||||
APPLICATION_DBG := bbirc-debug
|
||||
|
||||
$(shell mkdir -p $(BUILD_DIR))
|
||||
SRCS := $(wildcard $(SRC_DIR)/*.c)
|
||||
DBG_OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/dbg_%.o,$(SRCS))
|
||||
REL_OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/rel_%.o,$(SRCS))
|
||||
|
||||
.PHONY: all debug release clean
|
||||
|
||||
all: release
|
||||
|
||||
debug: $(APPLICATION_DBG)
|
||||
release: $(APPLICATION)
|
||||
both: debug release
|
||||
|
||||
$(APPLICATION): $(REL_OBJS)
|
||||
$(CC) -o $@ $^ $(LDFLAGS_REL)
|
||||
|
||||
$(APPLICATION_DBG): $(DBG_OBJS)
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(BUILD_DIR)/dbg_%.o: $(SRC_DIR)/%.c
|
||||
$(CC) -c -o $@ $^ $(CFLAGS_DBG)
|
||||
|
||||
$(BUILD_DIR)/rel_%.o: $(SRC_DIR)/%.c
|
||||
$(CC) -c -o $@ $^ $(CFLAGS_REL)
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
rm -rf $(APPLICATION)
|
||||
rm -rf $(APPLICATION_DBG)
|
||||
4
README.md
Normal file
4
README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# BareBones IRC
|
||||
An attempt at trying to make an IRC client in pure C with sockets.
|
||||
|
||||
**UNFINISHED!!!**
|
||||
5
TODO.md
Normal file
5
TODO.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# To-Do
|
||||
|
||||
1. Add actual IRC client functionality
|
||||
2. Finish the netcode
|
||||
3. Don't care about the looks of it yet, just have an ANSI command line or something
|
||||
BIN
build/rel_IRC.o
Normal file
BIN
build/rel_IRC.o
Normal file
Binary file not shown.
BIN
build/rel_main.o
Normal file
BIN
build/rel_main.o
Normal file
Binary file not shown.
BIN
build/rel_netcode.o
Normal file
BIN
build/rel_netcode.o
Normal file
Binary file not shown.
19
compile_commands.json
Normal file
19
compile_commands.json
Normal file
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"file": "src/main.c",
|
||||
"arguments": [
|
||||
"/usr/bin/clang",
|
||||
"-c",
|
||||
"-o",
|
||||
"build/rel_main.o",
|
||||
"src/main.c",
|
||||
"-I",
|
||||
"include",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-O2"
|
||||
],
|
||||
"directory": "/home/neon1246/Documents/stuff/code/c/ircclient",
|
||||
"output": "build/rel_main.o"
|
||||
}
|
||||
]
|
||||
39
include/IRC.h
Normal file
39
include/IRC.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef IRC_H
|
||||
#define IRC_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *nickname;
|
||||
int nicklen;
|
||||
char *ident;
|
||||
int identlen;
|
||||
char *hostname;
|
||||
int hostlen;
|
||||
|
||||
} irc_hostmask_t;
|
||||
|
||||
typedef struct {
|
||||
char line[513];
|
||||
char *source;
|
||||
char *command;
|
||||
char *argv[16];
|
||||
int argc;
|
||||
} irc_message_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sockfd;
|
||||
irc_hostmask_t ownHostmask;
|
||||
} irc_client_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
void (*handler)(irc_message_t *msg, irc_client_t *irc);
|
||||
} command_t;
|
||||
|
||||
int IRC_ParseMessage(char* line, irc_message_t *msg);
|
||||
void IRC_ProcessMessage(irc_message_t *msg, irc_client_t *irc);
|
||||
|
||||
void IRC_PRIVMSG(char* msg, irc_client_t irc);
|
||||
|
||||
#endif
|
||||
203
include/IRC_numerics.h
Normal file
203
include/IRC_numerics.h
Normal file
@@ -0,0 +1,203 @@
|
||||
#ifndef IRC_NUMERICS_H
|
||||
#define IRC_NUMERICS_H
|
||||
|
||||
// * 0xx (initial login information)
|
||||
#define RPL_WELCOME "001"
|
||||
#define RPL_YOURHOST "002"
|
||||
#define RPL_CREATED "003"
|
||||
#define RPL_MYINFO "004"
|
||||
#define RPL_ISUPPORT "005"
|
||||
#define RPL_BOUNCE "010" /* deprecated */
|
||||
|
||||
// * 2xx (request information)
|
||||
|
||||
/* replies to STATS */
|
||||
#define RPL_STATSCOMMANDS "212"
|
||||
#define RPL_ENDOFSTATS "219"
|
||||
#define RPL_STATSUPTIME "242"
|
||||
|
||||
/* server user modes on-connect */
|
||||
#define RPL_UMODEIS "221"
|
||||
|
||||
/* replies to LUSERS */
|
||||
#define RPL_LUSERCLIENT "251"
|
||||
#define RPL_LUSEROP "252"
|
||||
#define RPL_LUSERUNKNOWN "253"
|
||||
#define RPL_LUSERCHANNELS "254"
|
||||
#define RPL_LUSERME "255"
|
||||
#define RPL_LOCALUSERS "265"
|
||||
#define RPL_GLOBALUSERS "266"
|
||||
|
||||
/* replies to ADMIN */
|
||||
#define RPL_ADMINME "256"
|
||||
#define RPL_ADMINLOC1 "257"
|
||||
#define RPL_ADMINLOC2 "258"
|
||||
#define RPL_ADMINEMAIL "259"
|
||||
|
||||
/* generic replies (i.e. ratelimiting) */
|
||||
#define RPL_TRYAGAIN "263"
|
||||
|
||||
/* WHOIS info */
|
||||
#define RPL_WHOISCERTFP "276"
|
||||
|
||||
// * 3xx (information for clients)
|
||||
#define RPL_NONE "300"
|
||||
|
||||
/* replies to WHOIS/WHOWAS */
|
||||
#define RPL_AWAY "301"
|
||||
#define RPL_WHOISREGNICK "307"
|
||||
#define RPL_WHOISUSER "311"
|
||||
#define RPL_WHOISSERVER "312"
|
||||
#define RPL_WHOISOPERATOR "313"
|
||||
#define RPL_WHOWASUSER "314"
|
||||
#define RPL_WHOISIDLE "317"
|
||||
#define RPL_WHOISCHANNELS "319"
|
||||
#define RPL_WHOISSPECIAL "320"
|
||||
#define RPL_WHOISACCOUNT "330"
|
||||
#define RPL_WHOISACTUALLY "338"
|
||||
#define RPL_WHOISHOST "378"
|
||||
#define RPL_WHOISMODES "379"
|
||||
#define RPL_ENDOFWHOIS "318"
|
||||
#define RPL_ENDOFWHOWAS "369"
|
||||
#define ERR_WASNOSUCHNICK "406" /* WHOWAS error */
|
||||
#define RPL_WHOISSECURE "671"
|
||||
|
||||
/* replies to WHO */
|
||||
#define RPL_WHOREPLY "352"
|
||||
#define RPL_ENDOFWHO "315"
|
||||
|
||||
/* replies to LIST */
|
||||
#define RPL_LISTSTART "321"
|
||||
#define RPL_LIST "322"
|
||||
#define RPL_LISTEND "323"
|
||||
|
||||
/* upon joining a channel */
|
||||
#define RPL_CHANNELMODEIS "324"
|
||||
#define RPL_CREATIONTIME "329"
|
||||
#define RPL_TOPIC "332"
|
||||
#define RPL_TOPICWHOTIME "333"
|
||||
|
||||
/* replies to TOPIC */
|
||||
#define RPL_NOTOPIC "331"
|
||||
|
||||
/* replies to INVITE */
|
||||
#define RPL_INVITELIST "336"
|
||||
#define RPL_ENDOFINVITELIST "337"
|
||||
#define RPL_INVITING "341"
|
||||
|
||||
/* replies to MODE */
|
||||
#define RPL_INVEXLIST "346"
|
||||
#define RPL_ENDOFINVEXLIST "347"
|
||||
#define RPL_EXCEPTLIST "348"
|
||||
#define RPL_ENDOFEXCEPTLIST "349"
|
||||
#define RPL_BANLIST "367"
|
||||
#define RPL_ENDOFBANLIST "368"
|
||||
#define ERR_INVALIDMODEPARAM "696"
|
||||
|
||||
/* replies to INFO */
|
||||
#define RPL_INFO "371"
|
||||
#define RPL_ENDOFINFO "374"
|
||||
|
||||
/* when sending a Message of the Day */
|
||||
#define RPL_MOTDSTART "375"
|
||||
#define RPL_MOTD "372"
|
||||
#define RPL_ENDOFMOTD "376"
|
||||
|
||||
/* replies to VERSION */
|
||||
#define RPL_VERSION "351"
|
||||
|
||||
/* replies to NAMES */
|
||||
#define RPL_NAMREPLY "353"
|
||||
#define RPL_ENDOFNAMES "366"
|
||||
|
||||
/* replies to LINKS */
|
||||
#define RPL_LINKS "364"
|
||||
#define RPL_ENDOFLINKS "365"
|
||||
|
||||
/* replies to OPER */
|
||||
#define RPL_YOUREOPER "381"
|
||||
|
||||
/* replies to REHASH */
|
||||
#define RPL_REHASHING "382"
|
||||
|
||||
/* replies to TIME */
|
||||
#define RPL_TIME "391"
|
||||
|
||||
/* replies to USERHOST */
|
||||
#define RPL_USERHOST "302"
|
||||
|
||||
/* sent to clients to inform of away status */
|
||||
#define RPL_UNAWAY "305"
|
||||
#define RPL_NOWAWAY "306"
|
||||
|
||||
// * 4xx and 5xx (errors)
|
||||
|
||||
#define ERR_UNKNOWNERROR "400"
|
||||
#define ERR_NOSUCHNICK "401"
|
||||
#define ERR_NOSUCHSERVER "402"
|
||||
#define ERR_NOSUCHCHANNEL "403"
|
||||
#define ERR_CANNOTSENDTOCHAN "404"
|
||||
#define ERR_TOOMANYCHANNELS "405"
|
||||
#define ERR_NOORIGIN "409"
|
||||
#define ERR_NORECIPIENT "411"
|
||||
#define ERR_NOTEXTTOSEND "412"
|
||||
#define ERR_INPUTTOOLONG "417"
|
||||
#define ERR_UNKNOWNCOMMAND "421"
|
||||
#define ERR_NOMOTD "422"
|
||||
#define ERR_NONICKNAMEGIVEN "431"
|
||||
#define ERR_ERRONEUSNICKNAME "432"
|
||||
#define ERR_NICKNAMEINUSE "433"
|
||||
#define ERR_NICKCOLLISION "436"
|
||||
#define ERR_USERNOTINCHANNEL "441"
|
||||
#define ERR_NOTONCHANNEL "442"
|
||||
#define ERR_USERONCHANNEL "443"
|
||||
#define ERR_NOTREGISTERED "451"
|
||||
#define ERR_NEEDMOREPARAMS "461"
|
||||
#define ERR_ALREADYREGISTERED "462"
|
||||
#define ERR_PASSWDMISMATCH "464"
|
||||
#define ERR_YOUREBANNEDCREEP "465"
|
||||
#define ERR_CHANNELISFULL "471"
|
||||
#define ERR_UNKNOWNMODE "472"
|
||||
#define ERR_INVITEONLYCHAN "473"
|
||||
#define ERR_BANNEDFROMCHAN "474"
|
||||
#define ERR_BADCHANNELKEY "475"
|
||||
#define ERR_BADCHANMASK "476"
|
||||
#define ERR_NOPRIVILEGES "481"
|
||||
#define ERR_CHANOPRIVSNEEDED "482"
|
||||
#define ERR_CANTKILLSERVER "483"
|
||||
#define ERR_NOOPERHOST "491"
|
||||
#define ERR_UMODEUNKNOWNFLAG "501"
|
||||
#define ERR_USERSDONTMATCH "502"
|
||||
#define ERR_INVALIDKEY "525"
|
||||
|
||||
/* replies to HELP */
|
||||
#define ERR_HELPNOTFOUND "524"
|
||||
#define RPL_HELPSTART "704"
|
||||
#define RPL_HELPTXT "705"
|
||||
#define RPL_ENDOFHELP "706"
|
||||
|
||||
// * 6xx (various TLS and IRCv3 stuff)
|
||||
|
||||
/* STARTTLS stuff */
|
||||
#define RPL_STARTTLS "670"
|
||||
#define ERR_STARTTLS "691"
|
||||
|
||||
// * 7xx (various)
|
||||
|
||||
#define ERR_NOPRIVS "723"
|
||||
|
||||
// * 9xx (authentication)
|
||||
|
||||
/* SASL */
|
||||
#define RPL_LOGGEDIN "900"
|
||||
#define RPL_LOGGEDOUT "901"
|
||||
#define RPL_SASLSUCCESS "903"
|
||||
#define ERR_NICKLOCKED "902"
|
||||
#define ERR_SASLFAIL "904"
|
||||
#define ERR_SASLTOOLONG "905"
|
||||
#define ERR_SASLABORTED "906"
|
||||
#define ERR_SASLALREADY "907"
|
||||
#define RPL_SASLMECHS "908"
|
||||
|
||||
|
||||
#endif
|
||||
6
include/defines.h
Normal file
6
include/defines.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
#define NUL '\0'
|
||||
|
||||
#endif
|
||||
9
include/netcode.h
Normal file
9
include/netcode.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef NETCODE_H
|
||||
#define NETCODE_H
|
||||
|
||||
// Returns a socket file descriptor.
|
||||
int NET_Connect(const char* host, int port);
|
||||
void NET_Send(int sockfd, const char* toSend);
|
||||
void NET_Close(int sockfd);
|
||||
|
||||
#endif
|
||||
92
src/IRC.c
Normal file
92
src/IRC.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "IRC.h"
|
||||
#include "defines.h"
|
||||
#include "netcode.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int IRC_ParseMessage(char *line, irc_message_t *msg)
|
||||
{
|
||||
strncpy(msg->line, line, sizeof(msg->line) - 1);
|
||||
char *ptr = msg->line;
|
||||
ptr[sizeof(msg->line)] = NUL;
|
||||
|
||||
char *source = NULL;
|
||||
char *command = NULL;
|
||||
|
||||
// get the source, if it exists (the : at the beginning of an IRC message)
|
||||
if(*ptr == ':')
|
||||
{
|
||||
ptr++;
|
||||
source = ptr;
|
||||
|
||||
while (*ptr && *ptr != ' ') ptr++;
|
||||
if (*ptr) *ptr++ = NUL;
|
||||
|
||||
while (*ptr == ' ') ptr++; // skip any extra spaces
|
||||
}
|
||||
|
||||
msg->source = source;
|
||||
|
||||
// read the command
|
||||
command = ptr;
|
||||
|
||||
while(*ptr && *ptr != ' ') ptr++;
|
||||
if (*ptr) *ptr++ = NUL;
|
||||
|
||||
msg->command = command;
|
||||
|
||||
while (*ptr == ' ') ptr++;
|
||||
|
||||
// read its arguments (until we encounter a colon/nullbyte)
|
||||
msg->argc = 0;
|
||||
|
||||
while(*ptr && msg->argc <= 15)
|
||||
{
|
||||
if(*ptr == ':') // if it's a trailing arg
|
||||
{
|
||||
ptr++;
|
||||
msg->argv[msg->argc] = ptr;
|
||||
msg->argc++;
|
||||
break;
|
||||
}
|
||||
|
||||
msg->argv[msg->argc] = ptr;
|
||||
|
||||
while(*ptr && *ptr != ' ') ptr++;
|
||||
|
||||
if (*ptr)
|
||||
{
|
||||
*ptr++ = NUL;
|
||||
while (*ptr == ' ') ptr++; // skip spaces for next arg
|
||||
}
|
||||
|
||||
msg->argc++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handlePing(irc_message_t *msg, irc_client_t *irc)
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof buf, "PONG :%s", msg->argv[0]);
|
||||
NET_Send(irc->sockfd, buf);
|
||||
}
|
||||
|
||||
void IRC_ProcessMessage(irc_message_t *msg, irc_client_t *irc)
|
||||
{
|
||||
command_t commands[] =
|
||||
{
|
||||
{"PING", handlePing},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
for(int i = 0; commands[i].name; i++)
|
||||
{
|
||||
if(strcmp(msg->command, commands[i].name) == 0)
|
||||
{
|
||||
commands[i].handler(msg, irc);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/main.c
Normal file
105
src/main.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "IRC.h"
|
||||
#include "defines.h"
|
||||
#include "netcode.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sockfd = NET_Connect("irc.libera.chat", 6667);
|
||||
|
||||
fd_set readfds;
|
||||
static char linebuf[1026];
|
||||
static size_t lineLen = 0;
|
||||
char recvline[513];
|
||||
char sendline[513];
|
||||
|
||||
irc_client_t irc;
|
||||
irc.sockfd = sockfd;
|
||||
|
||||
if(sockfd >= 0)
|
||||
{
|
||||
NET_Send(sockfd, "NICK BareBonesDude\r\n");
|
||||
NET_Send(sockfd, "USER BareBonesDude 0 * :The Postal Dudesksleton\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(STDIN_FILENO, &readfds);
|
||||
FD_SET(sockfd, &readfds);
|
||||
|
||||
int maxfd = (sockfd > 0) ? sockfd + 1 : 1;
|
||||
|
||||
select(maxfd, &readfds, NULL, NULL, NULL);
|
||||
|
||||
if(FD_ISSET(STDIN_FILENO, &readfds))
|
||||
{
|
||||
fgets(sendline, sizeof(sendline), stdin);
|
||||
NET_Send(sockfd, sendline);
|
||||
}
|
||||
|
||||
if(FD_ISSET(sockfd, &readfds))
|
||||
{
|
||||
ssize_t n = recv(sockfd, recvline, sizeof(recvline), 0);
|
||||
|
||||
if(n <= 0) break;
|
||||
recvline[n] = NUL;
|
||||
|
||||
for(ssize_t i = 0; i < n; i++)
|
||||
{
|
||||
linebuf[lineLen++] = recvline[i];
|
||||
|
||||
if(lineLen >= 2 && linebuf[lineLen - 2] == '\r' && linebuf[lineLen - 1] == '\n')
|
||||
{
|
||||
// we found a complete line
|
||||
linebuf[lineLen] = NUL;
|
||||
|
||||
// parse the message
|
||||
irc_message_t msg;
|
||||
IRC_ParseMessage(linebuf, &msg);
|
||||
|
||||
// try to print it
|
||||
|
||||
if(msg.source != NULL)
|
||||
{
|
||||
printf("%s: %s ", msg.source, msg.command);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Server: %s ", msg.command);
|
||||
}
|
||||
|
||||
for(int i = 0; i < msg.argc; i++)
|
||||
{
|
||||
printf("%s ", msg.argv[i]);
|
||||
}
|
||||
|
||||
lineLen = 0;
|
||||
}
|
||||
|
||||
if(lineLen >= sizeof(linebuf) - 1)
|
||||
{
|
||||
lineLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Connection closed by foreign host.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
123
src/netcode.c
Normal file
123
src/netcode.c
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "netcode.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
int NET_Connect(const char *host, int port)
|
||||
{
|
||||
int status;
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
// save us from user or programmer stupidity
|
||||
if(!host)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char portNumber[6];
|
||||
snprintf(portNumber, 6, "%d", port);
|
||||
|
||||
printf("Looking up %s...\n", host);
|
||||
|
||||
if ((status = getaddrinfo(host, portNumber, &hints, &res)) == -1)
|
||||
{
|
||||
fprintf(stderr, "Unable to lookup %s: %s\n", host, gai_strerror(status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
int sockfd = -1;
|
||||
|
||||
for(struct addrinfo *p = res; p != NULL; p = p->ai_next)
|
||||
{
|
||||
void *addr;
|
||||
struct sockaddr_in *ipv4;
|
||||
struct sockaddr_in6 *ipv6;
|
||||
|
||||
if(p->ai_family == AF_INET)
|
||||
{
|
||||
ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
addr = &(ipv4->sin_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
addr = &(ipv6->sin6_addr);
|
||||
}
|
||||
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
printf("Connecting to %s (%s)...\n", host, ipstr);
|
||||
|
||||
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
|
||||
{
|
||||
char perrorMsg[sizeof("Failed to connect to ") + sizeof ipstr];
|
||||
snprintf(perrorMsg, sizeof perrorMsg, "Failed to connect to %s", ipstr);
|
||||
perror(perrorMsg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if((connect(sockfd, p->ai_addr, p->ai_addrlen)) == -1)
|
||||
{
|
||||
close(sockfd);
|
||||
char perrorMsg[sizeof("Failed to connect to ") + sizeof ipstr];
|
||||
snprintf(perrorMsg, sizeof perrorMsg, "Failed to connect to %s", ipstr);
|
||||
perror(perrorMsg);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Connected!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(sockfd >= 0)
|
||||
{
|
||||
return sockfd;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void NET_Send(int sockfd, const char *toSend)
|
||||
{
|
||||
size_t bytesSent = 0;
|
||||
size_t sendLen = strlen(toSend);
|
||||
|
||||
while(bytesSent < sendLen)
|
||||
{
|
||||
ssize_t sent = send(sockfd, toSend, sendLen - bytesSent, 0);
|
||||
if(sent == -1)
|
||||
{
|
||||
perror("NET_Send");
|
||||
return;
|
||||
}
|
||||
|
||||
if(sent == 0)
|
||||
{
|
||||
fprintf(stderr, "NET_Send: connection closed");
|
||||
return;
|
||||
}
|
||||
|
||||
bytesSent += sent;
|
||||
}
|
||||
}
|
||||
|
||||
void NET_Close(int sockfd)
|
||||
{
|
||||
if(sockfd >= 0)
|
||||
{
|
||||
shutdown(sockfd, SHUT_RDWR);
|
||||
close(sockfd);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user