#include #include #include #include #include #include #include #include #include #include #include #include enum read_modes { READ_NORMAL, READ_BLOCKED, READ_FULL }; struct line_buffer { int handle; int buf_used; int buf_size; void *buffer; }; static int n_line_buffers = 0; static struct line_buffer *linebuf = NULL; static void linebuf_out_of_memory(void) /* {{{ */ { fputs(__FILE__, stderr); fputs("out of memory\n", stderr); exit(128); } /* }}} */ static int linebuf_append(int handle, void *buffer, int size) /* {{{ */ { register int i, handle_idx = -1; for (i = 0; i < n_line_buffers; i++) if (linebuf[i].handle == handle) handle_idx = i; if (handle_idx == -1) { linebuf = (struct line_buffer *) realloc((void *) linebuf, (i + 1) * sizeof(struct line_buffer)); if (linebuf == NULL) linebuf_out_of_memory(); linebuf[i].handle = handle; linebuf[i].buf_used = 0; linebuf[i].buf_size = 0; linebuf[i].buffer = NULL; } if (linebuf[i].buf_size - linebuf[i].buf_used < size || linebuf[i].buffer == NULL) { linebuf[i].buf_size = linebuf[i].buf_used + max(size, 20); linebuf[i].buffer = (char *) realloc((void *) linebuf[i].buffer, linebuf[i].buf_size * sizeof(char)); if (linebuf[i].buffer == NULL) linebuf_out_of_memory(); } memcpy((void *) ((char *) linebuf[i].buffer + linebuf[i].buf_used), buffer, size); linebuf[i].buf_used += size; return size; } /* }}} */ static int linebuf_fetch(int handle, void *buffer, int size) /* {{{ */ { register int i, handle_idx = -1, bytes_fetched; for (i = 0; i < n_line_buffers; i++) if (linebuf[i].handle == handle) handle_idx = i; if (handle_idx == -1) return 0; bytes_fetched = min(linebuf[i].buf_used, size); memcpy(buffer, linebuf[i].buffer, bytes_fetched); linebuf[i].buf_used -= bytes_fetched; return bytes_fetched; } /* }}} */ int net_connection_open(const char *host, int port) /* {{{ */ { int sock; struct sockaddr_in sin; struct hostent *he; he = gethostbyname(host); #if NET_CONNECTION_DEBUG fprintf(stderr, "net_connection_connect()\n"); if (he == NULL) fprintf(stderr, " ERROR: unknown host: %s\n", host); else fprintf(stderr, " OK: host found: %s\n",host); #endif if (he == NULL) return -1; if (port <= 0) { #if NET_CONNECTION_DEBUG fprintf(stderr, " ERROR: bad port: %d\n", port); #endif return -1; } sock = socket(PF_INET, SOCK_STREAM, 0); #if NET_CONNECTION_DEBUG if (sock == -1) fprintf(stderr, " ERROR: can't create socket\n"); else fprintf(stderr, " OK: socket created\n"); #endif if (sock == -1) return -1; sin.sin_family = AF_INET; sin.sin_addr.s_addr = *((unsigned int *) he->h_addr); sin.sin_port = htons(port); #if NET_CONNECTION_DEBUG fprintf(stderr," STATUS: Trying to connect...\n"); #endif if (connect(sock, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) == -1) { #if NET_CONNECTION_DEBUG fprintf(stderr," ERROR: cannot connect\n"); #endif return -1; } #if NET_CONNECTION_DEBUG fprintf(stderr," OK: connection estabilished\n"); #endif return sock; } /* }}} */ void net_connection_close(int *handle) /* {{{ */ { if (*handle > 0) close(*handle); *handle = -1; return; } /* }}} */ int net_connection_is_open(int *handle) /* {{{ */ { return *handle > 0; } /* }}} */ static int __net_connection_read(int *handle, void *buffer, int size, int mode) /* {{{ */ { register int ret, to_read; struct timeval tv; fd_set read_set; if (! net_connection_is_open(handle)) return 0; if (size <= 0) return 0; for (to_read = size; to_read > 0; ) { if (mode == READ_BLOCKED && to_read != size) mode = READ_NORMAL; FD_ZERO(&read_set); FD_SET(*handle, &read_set); if (mode == READ_NORMAL) { tv.tv_sec = 0; tv.tv_usec = 0; ret = select(*handle + 1, &read_set, NULL, NULL, &tv); } else { ret = select(*handle + 1, &read_set, NULL, NULL, NULL); } if (ret <= 0) { if (ret < 0) net_connection_close(handle); break; } ret = read(*handle, (void *) ((char *) buffer + size - to_read), to_read); if (ret <= 0) { net_connection_close(handle); break; } to_read -= ret; } return size - to_read; } /* }}} */ int net_connection_read(int *handle, void *buffer, int size) /* {{{ */ { return __net_connection_read(handle, buffer, size, READ_NORMAL); } /* }}} */ int net_connection_read_blocked(int *handle, void *buffer, int size) /* {{{ */ { return __net_connection_read(handle, buffer, size, READ_BLOCKED); } /* }}} */ int net_connection_read_full(int *handle, void *buffer, int size) /* {{{ */ { return __net_connection_read(handle, buffer, size, READ_FULL); } /* }}} */ int net_connection_gets(int *handle, char *buffer, int size) { register int ret, to_read, bytes_read, linebuf_fetched = 0; register char *str_eos, *str_eol; for (to_read = size - 1, bytes_read = 0, str_eos = str_eol = NULL; net_connection_is_open(handle) && to_read > 0 && str_eos == NULL && str_eol == NULL; ) { if (linebuf_fetched) { ret = net_connection_read(handle, (void *) (buffer + size - to_read - 1), to_read); if (ret == 0) break; } else { ret = linebuf_fetch(*handle, (void *) (buffer + size - to_read - 1), to_read); linebuf_fetched = 1; } to_read -= ret; bytes_read += ret; str_eos = (char *) memchr((void *) buffer, '\0', bytes_read); str_eol = (char *) memchr((void *) buffer, '\n', bytes_read); } if (str_eos == NULL && str_eol == NULL) { if (bytes_read == size) buffer[bytes_read] = '\0'; else { linebuf_append(*handle, buffer, bytes_read); buffer[0] = '\0'; } } else { register int bytes_used; if (str_eos != NULL && str_eol != NULL) { str_eos = str_eos > str_eol ? NULL : str_eos; str_eol = str_eol > str_eos ? NULL : str_eol; } if (str_eos != NULL) { bytes_used = str_eos - buffer + 1; linebuf_append(*handle, str_eos + 1, bytes_read - bytes_used); } if (str_eol != NULL) { bytes_used = str_eol - buffer + 1; linebuf_append(*handle, str_eos + 1, bytes_read - bytes_used); *(str_eol + 1) = '\0'; } } return strlen(buffer); } #if 0 int net_connection_gets_blocked(int *handle, char *buffer, int size) { return 0; } int net_connection_gets(int handle,char*buffer,int size){ register int ret; if(__net_connection_buffer!=NULL){ strncpy(buffer,__net_connection_buffer,size-1); buffer[size-1]='\0'; } else buffer[0]='\0'; if((int)strlen(buffer)<(size-1)){ ret=net_connection_read(handle,strchr(buffer,'\0'),size-strlen(buffer)-1); } else ret=1; if(ret>=0){ if(strstr(buffer,NET_CONNECTION_EOL)!=NULL){ __net_connection_buffer = (char*)realloc(__net_connection_buffer,(strlen(strstr(buffer,NET_CONNECTION_EOL)+strlen(NET_CONNECTION_EOL))+1)*sizeof(char)); strcpy(__net_connection_buffer,strstr(buffer,NET_CONNECTION_EOL)+strlen(NET_CONNECTION_EOL)); *(strstr(buffer,NET_CONNECTION_EOL)+strlen(NET_CONNECTION_EOL))='\0'; } else{ if(__net_connection_buffer!=NULL){ if(strlen(buffer) #define BUFSIZE 10 int main(int argc, char **argv) { register int port = 25; char *server = "localhost", buffer[BUFSIZE]; int handle, ret; handle = net_connection_open(server, port); if (handle < 0) { fprintf(stderr, "cannot connect to %s:%d\n", server, port); return 1; } printf("net_connection_read() test\n"); printf("fetching first %d bytes from connection:\n", BUFSIZE - 1); while (net_connection_is_open(&handle) && (ret = net_connection_read(&handle, buffer, BUFSIZE - 1)) == 0) ; buffer[ret] = '\0'; printf(">>> [%s] (%d characters)\n", buffer, ret); while (net_connection_is_open(&handle)) { ret = net_connection_gets(&handle, buffer, BUFSIZE); if (ret > 0) printf("[%s] (%d characters)\n", buffer, ret); } net_connection_close(&handle); return 0; } #endif /* Modeline for ViM {{{ * vim: set ts=4: * vim600: fdm=marker fdl=0 fdc=0: * }}} */