/*------- * Module: socket.c * * Description: This module contains functions for low level socket * operations (connecting/reading/writing to the backend) * * Classes: SocketClass (Functions prefix: "SOCK_") * * API functions: none * * Comments: See "notice.txt" for copyright and license information. *------- */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "socket.h" #ifndef WIN32 #include <stdlib.h> #include <string.h> /* for memset */ #endif extern GLOBAL_VALUES globals; #ifndef BOOL #define BOOL int #endif #ifndef TRUE #define TRUE (BOOL)1 #endif #ifndef FALSE #define FALSE (BOOL)0 #endif void SOCK_clear_error(SocketClass *self) { self->errornumber = 0; self->errormsg = NULL; } SocketClass * SOCK_Constructor() { SocketClass *rv; rv = (SocketClass *) malloc(sizeof(SocketClass)); if (rv != NULL) { rv->socket = (SOCKETFD) - 1; rv->buffer_filled_in = 0; rv->buffer_filled_out = 0; rv->buffer_read_in = 0; rv->buffer_in = (unsigned char *) malloc(globals.socket_buffersize); if (!rv->buffer_in) { free(rv); return NULL; } rv->buffer_out = (unsigned char *) malloc(globals.socket_buffersize); if (!rv->buffer_out) { free(rv->buffer_in); free(rv); return NULL; } rv->errormsg = NULL; rv->errornumber = 0; rv->reverse = FALSE; } return rv; } void SOCK_Destructor(SocketClass *self) { if (self->socket != -1) { SOCK_put_char(self, 'X'); SOCK_flush_output(self); closesocket(self->socket); } if (self->buffer_in) free(self->buffer_in); if (self->buffer_out) free(self->buffer_out); free(self); } char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) { struct hostent *host; struct sockaddr_in sadr; unsigned long iaddr; if (self->socket != -1) { self->errornumber = SOCKET_ALREADY_CONNECTED; self->errormsg = "Socket is already connected"; return 0; } memset((char *) &sadr, 0, sizeof(sadr)); /* * If it is a valid IP address, use it. Otherwise use hostname lookup. */ iaddr = inet_addr(hostname); if (iaddr == INADDR_NONE) { host = gethostbyname(hostname); if (host == NULL) { self->errornumber = SOCKET_HOST_NOT_FOUND; self->errormsg = "Could not resolve hostname."; return 0; } memcpy(&(sadr.sin_addr), host->h_addr, host->h_length); } else memcpy(&(sadr.sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr)); sadr.sin_family = AF_INET; sadr.sin_port = htons(port); self->socket = socket(AF_INET, SOCK_STREAM, 0); if (self->socket == -1) { self->errornumber = SOCKET_COULD_NOT_CREATE_SOCKET; self->errormsg = "Could not create Socket."; return 0; } if (connect(self->socket, (struct sockaddr *) & (sadr), sizeof(sadr)) < 0) { self->errornumber = SOCKET_COULD_NOT_CONNECT; self->errormsg = "Could not connect to remote socket."; closesocket(self->socket); self->socket = (SOCKETFD) - 1; return 0; } return 1; } void SOCK_get_n_char(SocketClass *self, char *buffer, int len) { int lf; if (!buffer) { self->errornumber = SOCKET_NULLPOINTER_PARAMETER; self->errormsg = "get_n_char was called with NULL-Pointer"; return; } for (lf = 0; lf < len; lf++) buffer[lf] = SOCK_get_next_byte(self); } void SOCK_put_n_char(SocketClass *self, char *buffer, int len) { int lf; if (!buffer) { self->errornumber = SOCKET_NULLPOINTER_PARAMETER; self->errormsg = "put_n_char was called with NULL-Pointer"; return; } for (lf = 0; lf < len; lf++) SOCK_put_next_byte(self, (unsigned char) buffer[lf]); } /* * bufsize must include room for the null terminator * will read at most bufsize-1 characters + null. * returns TRUE if truncation occurs. */ BOOL SOCK_get_string(SocketClass *self, char *buffer, int bufsize) { register int lf = 0; for (lf = 0; lf < bufsize; lf++) if (!(buffer[lf] = SOCK_get_next_byte(self))) return FALSE; buffer[bufsize - 1] = '\0'; return TRUE; } void SOCK_put_string(SocketClass *self, char *string) { register int lf; int len; len = strlen(string) + 1; for (lf = 0; lf < len; lf++) SOCK_put_next_byte(self, (unsigned char) string[lf]); } int SOCK_get_int(SocketClass *self, short len) { switch (len) { case 2: { unsigned short buf; SOCK_get_n_char(self, (char *) &buf, len); if (self->reverse) return buf; else return ntohs(buf); } case 4: { unsigned int buf; SOCK_get_n_char(self, (char *) &buf, len); if (self->reverse) return buf; else return ntohl(buf); } default: self->errornumber = SOCKET_GET_INT_WRONG_LENGTH; self->errormsg = "Cannot read ints of that length"; return 0; } } void SOCK_put_int(SocketClass *self, int value, short len) { unsigned int rv; switch (len) { case 2: rv = self->reverse ? value : htons((unsigned short) value); SOCK_put_n_char(self, (char *) &rv, 2); return; case 4: rv = self->reverse ? value : htonl((unsigned int) value); SOCK_put_n_char(self, (char *) &rv, 4); return; default: self->errornumber = SOCKET_PUT_INT_WRONG_LENGTH; self->errormsg = "Cannot write ints of that length"; return; } } void SOCK_flush_output(SocketClass *self) { int written; written = send(self->socket, (char *) self->buffer_out, self->buffer_filled_out, 0); if (written != self->buffer_filled_out) { self->errornumber = SOCKET_WRITE_ERROR; self->errormsg = "Could not flush socket buffer."; } self->buffer_filled_out = 0; } unsigned char SOCK_get_next_byte(SocketClass *self) { if (self->buffer_read_in >= self->buffer_filled_in) { /* * there are no more bytes left in the buffer so reload the buffer */ self->buffer_read_in = 0; self->buffer_filled_in = recv(self->socket, (char *) self->buffer_in, globals.socket_buffersize, 0); mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, globals.socket_buffersize); if (self->buffer_filled_in < 0) { self->errornumber = SOCKET_READ_ERROR; self->errormsg = "Error while reading from the socket."; self->buffer_filled_in = 0; return 0; } if (self->buffer_filled_in == 0) { self->errornumber = SOCKET_CLOSED; self->errormsg = "Socket has been closed."; self->buffer_filled_in = 0; return 0; } } return self->buffer_in[self->buffer_read_in++]; } void SOCK_put_next_byte(SocketClass *self, unsigned char next_byte) { int bytes_sent; self->buffer_out[self->buffer_filled_out++] = next_byte; if (self->buffer_filled_out == globals.socket_buffersize) { /* buffer is full, so write it out */ bytes_sent = send(self->socket, (char *) self->buffer_out, globals.socket_buffersize, 0); if (bytes_sent != globals.socket_buffersize) { self->errornumber = SOCKET_WRITE_ERROR; self->errormsg = "Error while writing to the socket."; } self->buffer_filled_out = 0; } }