commit f7f20a74dd85bafbf0350d9be0556abbd13ec81b
parent ccbb30dd2e6c844c9333a1bf3307e8f559717dee
Author: Mario Rosell R. Martinez <mario@mariorosell.es>
Date: Wed, 18 Mar 2026 20:33:35 +0100
Add write.
Diffstat:
| M | .gitignore | | | 3 | +-- |
| M | anntp.h | | | 222 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
2 files changed, 139 insertions(+), 86 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,5 +1,4 @@
-test.c
-*.o
+*.c
a.out
thumbs.db
.DS_Store
diff --git a/anntp.h b/anntp.h
@@ -5,36 +5,46 @@
#ifndef ANNTP_H
#define ANNTP_H
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <unistd.h>
+#include <arpa/inet.h> /* for inet_ntoa, inet_ntop */
+#include <netdb.h> /* for gethostbyname, struct hostent */
+#include <netinet/in.h> /* for struct in_addr */
+#include <stddef.h> /* for size_t */
+#include <stdio.h> /* for fprintf, perror, stderr */
+#include <stdlib.h> /* for malloc, free */
+#include <string.h> /* for memset, memcpy, strdup */
+#include <sys/socket.h> /* for socket, connect */
+#include <unistd.h> /* for close */
+#include <fcntl.h> /* for fcntl */
+
+#ifdef ANNTP_TLS
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+
+/*** config ***/
#ifdef _WIN32
-# error This project uses the Anntp library, which is not compatible with Windows
+# error This project uses the Anntp library, which is not compatible with Windows, sorry :(
#endif
#ifndef ANNTP_MALLOC
-# define ANNTP_MALLOC malloc
+# define ANNTP_MALLOC malloc
#endif
#ifndef ANNTP_FREE
-# define ANNTP_FREE free
+# define ANNTP_FREE free
#endif
#ifndef ANNTP_BUFSIZE
-# define ANNTP_BUFSIZE 0x1000
+# define ANNTP_BUFSIZE 0x1000
#endif
#ifndef ANNTP_API
-# define ANNTP_API extern
+# define ANNTP_API extern
#endif
+/*** defs ***/
+
#define Bool int
#define true 1
#define false 0
@@ -51,73 +61,79 @@ enum anntp_state {
typedef enum anntp_state AnntpState;
struct anntp_connection {
- int fd;
- AnntpState state;
- Bool use_tls;
+ int fd; /* socket file descriptor */
+ AnntpState state; /* current connection state */
+ Bool use_tls; /* whether to use TLS */
+ char* host; /* hostname string */
+ struct hostent* host_he; /* resolved host entry */
+ struct in_addr addr; /* resolved IP address */
+ uchar_t read_buffer[ANNTP_BUFSIZE]; /* read buffer */
+ size_t read_len; /* length of data in buffer */
#ifdef ANNTP_TLS
- void* ssl;
- void* ssl_ctx;
+ SSL* ssl; /* TLS session */
#endif
- char* host;
- struct in_addr addr;
- uchar_t rbuf[ANNTP_BUFSIZE];
- size_t rbuf_elen;
};
typedef struct anntp_connection AnntpConnection;
-ANNTP_API void anntp_init(void);
+/*** function declarations ***/
+
+ANNTP_API void anntp_init(void);
ANNTP_API AnntpConnection* anntp_mkconn(const char* host, const char* port, Bool tls);
-ANNTP_API void anntp_freeconn(AnntpConnection* conn);
-ANNTP_API ssize_t anntp_read(AnntpConnection* conn, uchar_t* buf, size_t bufsize);
-ANNTP_API ssize_t anntp_write(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
+ANNTP_API void anntp_freeconn(AnntpConnection* conn);
+ANNTP_API ssize_t anntp_read(AnntpConnection* conn, uchar_t* buf, size_t bufsize);
+ANNTP_API ssize_t anntp_write(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
+ANNTP_API ssize_t anntp_write_all(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
+ANNTP_API ssize_t anntp_write_line(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
+ANNTP_API ssize_t anntp_readline(AnntpConnection* conn, char* buf, size_t maxlen);
#endif /* ANNTP_H */
#ifdef ANNTP_IMPLEMENTATION
-#ifdef ANNTP_TLS
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#endif
-
void
anntp_init(void)
{
#ifdef ANNTP_TLS
- SSL_library_init();
SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
+ SSL_library_init();
+ OpenSSL_add_ssl_algorithms();
#endif
}
+/* create connection */
AnntpConnection*
anntp_mkconn(const char* host, const char* port, Bool tls)
{
AnntpConnection* cv = (AnntpConnection*)ANNTP_MALLOC(sizeof(AnntpConnection));
- if (!cv)
- return NULL;
+ if (!cv) return NULL;
memset(cv, 0, sizeof(*cv));
cv->host = strdup(host);
cv->use_tls = tls;
cv->state = ANS_OFF;
+ /* create socket */
cv->fd = socket(AF_INET, SOCK_STREAM, 0);
if (cv->fd < 0) {
- perror("anntp - socket");
+ perror("anntp - making socket");
goto cleanup;
}
+ /* make socket blocking for greeting */
+ int flags = fcntl(cv->fd, F_GETFL, 0);
+ flags &= ~O_NONBLOCK;
+ fcntl(cv->fd, F_SETFL, flags);
+
+ /* resolve host */
struct addrinfo hints, *res = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
int err = getaddrinfo(host, port, &hints, &res);
- if (err != 0) {
+ if (err != 0 || !res) {
fprintf(stderr, "anntp - cant resolve host `%s': %s\n", host, gai_strerror(err));
- close(cv->fd);
goto cleanup;
}
@@ -125,52 +141,41 @@ anntp_mkconn(const char* host, const char* port, Bool tls)
cv->addr = sa->sin_addr;
if (connect(cv->fd, (struct sockaddr*)sa, sizeof(*sa)) < 0) {
- perror("anntp - connect");
- close(cv->fd);
- freeaddrinfo(res);
- goto cleanup;
+ perror("anntp - connect failed");
+ goto cleanup_addr;
}
- freeaddrinfo(res);
+ cv->state = ANS_CONNECTING;
#ifdef ANNTP_TLS
if (tls) {
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
- if (!ctx) {
- fprintf(stderr, "anntp - SSL_CTX_new failed\n");
- goto cleanup;
- }
+ if (!ctx) goto cleanup_addr;
- SSL* ssl = SSL_new(ctx);
- if (!ssl) {
- fprintf(stderr, "anntp - SSL_new failed\n");
- SSL_CTX_free(ctx);
- goto cleanup;
- }
+ cv->ssl = SSL_new(ctx);
+ if (!cv->ssl) goto cleanup_addr;
- SSL_set_fd(ssl, cv->fd);
- if (SSL_connect(ssl) <= 0) {
- ERR_print_errors_fp(stderr);
- SSL_free(ssl);
- SSL_CTX_free(ctx);
- goto cleanup;
+ SSL_set_fd(cv->ssl, cv->fd);
+ if (SSL_connect(cv->ssl) <= 0) {
+ SSL_free(cv->ssl);
+ cv->ssl = NULL;
+ goto cleanup_addr;
}
- cv->ssl = ssl;
- cv->ssl_ctx = ctx;
+ SSL_CTX_free(ctx);
}
#endif
- cv->state = ANS_CONNECTING;
+ cv->state = ANS_READY;
+
+ freeaddrinfo(res);
return cv;
+cleanup_addr:
+ freeaddrinfo(res);
cleanup:
-#ifdef ANNTP_TLS
- if (cv->ssl) SSL_free((SSL*)cv->ssl);
- if (cv->ssl_ctx) SSL_CTX_free((SSL_CTX*)cv->ssl_ctx);
-#endif
- if (cv->fd >= 0) close(cv->fd);
if (cv->host) ANNTP_FREE(cv->host);
+ if (cv->fd >= 0) close(cv->fd);
ANNTP_FREE(cv);
return NULL;
}
@@ -181,9 +186,10 @@ anntp_freeconn(AnntpConnection* cv)
if (!cv) return;
#ifdef ANNTP_TLS
- if (cv->ssl) SSL_shutdown((SSL*)cv->ssl);
- if (cv->ssl) SSL_free((SSL*)cv->ssl);
- if (cv->ssl_ctx) SSL_CTX_free((SSL_CTX*)cv->ssl_ctx);
+ if (cv->ssl) {
+ SSL_shutdown(cv->ssl);
+ SSL_free(cv->ssl);
+ }
#endif
if (cv->fd >= 0) close(cv->fd);
@@ -192,30 +198,78 @@ anntp_freeconn(AnntpConnection* cv)
}
ssize_t
-anntp_write(AnntpConnection* conn, const uchar_t* bytes, size_t len)
+anntp_read(AnntpConnection* cv, uchar_t* buf, size_t len)
{
- if (!conn || !bytes)
- return -1; /* idiot-proofing */
+ if (!cv || !buf) return -1;
- size_t total = 0;
+#ifdef ANNTP_TLS
+ if (cv->use_tls && cv->ssl) return SSL_read(cv->ssl, buf, (int)len);
+#endif
+
+ return read(cv->fd, buf, len);
+}
- while (total < len) {
- ssize_t n = 0;
+ssize_t
+anntp_write(AnntpConnection* cv, const uchar_t* buf, size_t len)
+{
+ if (!cv || !buf) return -1;
#ifdef ANNTP_TLS
- if (conn->use_tls)
- n = SSL_write((SSL*)conn->ssl, bytes + total, (int)(len - total));
- else
+ if (cv->use_tls && cv->ssl) return SSL_write(cv->ssl, buf, (int)len);
#endif
- n = write(conn->fd, bytes + total, len - total);
+ return write(cv->fd, buf, len);
+}
+
+ssize_t
+anntp_write_all(AnntpConnection* cv, const uchar_t* buf, size_t len)
+{
+ size_t sent = 0;
+ while (sent < len) {
+ ssize_t n = anntp_write(cv, buf + sent, len - sent);
+ if (n <= 0) return n;
+ sent += (size_t)n;
+ }
+ return (ssize_t)sent;
+}
+
+ssize_t
+anntp_readline(AnntpConnection* cv, char* buf, size_t maxlen)
+{
+ if (!cv || !buf || maxlen == 0) return -1;
+
+ size_t pos = 0;
+ while (pos < maxlen - 1) {
+ uchar_t c;
+ ssize_t n = anntp_read(cv, &c, 1);
if (n <= 0) {
- /* an error happened */
- return n;
+ if (pos == 0) return n;
+ break;
}
- total += n;
+ buf[pos++] = c;
+ if (c == '\n') break;
}
+
+ buf[pos] = '\0';
+ return (ssize_t)pos;
+}
+
+ssize_t
+anntp_writeline(AnntpConnection* cv, const char* line)
+{
+ if (!cv || !line) return -1;
+
+ size_t len = strlen(line);
+ ssize_t n;
+
+ /* write the line itself */
+ n = anntp_write_all(cv, (const uchar_t*)line, len);
+ if (n <= 0) return n;
+
+ /* write CRLF */
+ n = anntp_write_all(cv, (const uchar_t*)"\r\n", 2);
+ return n;
}
#endif /* ANNTP_IMPLEMENTATION */