?? tcp.c
字號:
/* * Copyright (C) 2006 Takeharu KATO * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include <stdio.h>#include <signal.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/socket.h>#include <sys/ioctl.h> #include <netinet/in.h>#include <netinet/tcp.h> #include <netdb.h>#include <errno.h>#include <glib.h>#include <unistd.h>#include <glib.h>#include <libgnomevfs/gnome-vfs.h>#include "common.h"static intdestroy_tcp_connection(tcp_con_t *con) { dbg_out("Here\n"); if (!con) return -EINVAL; if (con->self) freeaddrinfo(con->self); con->self=NULL; close(con->soc); return 0;}static intparse_request(request_msg_t *req,const char *request_string){ size_t len; long int_val; char *sp=NULL; char *ep=NULL; char *buffer; ssize_t remains; gboolean has_offset=FALSE; int rc=0; if ( (!request_string) || (!req) ) return -EINVAL; dbg_out("Here:%s\n",request_string); buffer=g_strdup(request_string); if (!buffer) return -ENOMEM; len=strlen(request_string); _assert(len>0); remains=len; /* * パケット番號 */ sp=buffer; ep=memchr(sp, ':', remains); if (!ep) { rc=-EINVAL; goto err_out; } *ep='\0'; remains =len - ((unsigned long)ep-(unsigned long)buffer); if (remains<=0) { rc=-EINVAL; goto err_out; } ++ep; int_val=strtol(sp, (char **)NULL, 16); req->pkt_no=int_val; dbg_out("pktno:%ld\n",req->pkt_no); sp=ep; /* * ファイルID */ ep=memchr(sp, ':', remains); if (ep) { has_offset=TRUE; *ep='\0'; remains =len - ((unsigned long)ep-(unsigned long)buffer); if (remains<=0) { rc=-EINVAL; goto err_out; } ++ep; } int_val=strtol(sp, (char **)NULL, 16); req->fileid=int_val; dbg_out("fileid:%d(%x)\n",req->fileid,req->fileid); sp=ep; /* * オフセット */ if (has_offset) int_val=strtol(sp, (char **)NULL, 16); else int_val=0; /* 仮に0にする */ req->offset=int_val; dbg_out("offset:%d(%x)\n",req->offset,req->offset);err_out: g_free(buffer); return rc;}static inttcp_ipmsg_finalize_connection(tcp_con_t *con){ int rc=0; char dummy[1]; g_assert(con); sock_set_buffer(con->soc); dbg_out("Wait for closing by peer.\n"); sock_set_recv_timeout(con->soc,TCP_CLOSE_WAIT_SEC); rc=wait_socket(con->soc,WAIT_FOR_READ,TCP_SELECT_SEC); if (rc<0) { dbg_out("OK timeout select :%s(%d)\n",strerror(errno),errno); return -errno; } memset(dummy, 0, sizeof(dummy)); rc=recv(con->soc, dummy,sizeof(dummy),0); /* 相手のクローズ検出 */ if (rc<0) dbg_out("OK timeout:%s(%d)\n",strerror(errno),errno); else rc=0; return rc;}static inttcp_transfer_file(tcp_con_t *con,const char *path,const size_t size,off_t offset){ int fd; int rc; char buff[TCP_FILE_BUFSIZ]; ssize_t read_len; ssize_t file_remains; ssize_t soc_remains; ssize_t write_len; size_t total_write; char *wp; struct sigaction saved_act; if ( (!con) || (!path) ) return -EINVAL; fd=open(path,O_RDONLY); if (fd<0) return -errno; rc=lseek(fd, offset, SEEK_SET); if (rc<0) { rc=-errno; goto close_out; } total_write=0; file_remains=size; while(file_remains>0) { read_len=read(fd,buff,TCP_FILE_BUFSIZ); if (read_len<0) { rc=-errno; err_out("Can not read file %s %d\n",strerror(errno),errno); goto close_out; } file_remains -= read_len; soc_remains=read_len; wp=buff; if (wait_socket(con->soc,WAIT_FOR_WRITE,TCP_SELECT_SEC)<0) { err_out("Can not send socket\n"); goto close_out; } dbg_out("sock remains:%d\n",soc_remains); while(soc_remains>0) { disable_pipe_signal(&saved_act); write_len=send(con->soc,wp,soc_remains,0); enable_pipe_signal(&saved_act); if (write_len<0) { if (errno==EINTR) continue; err_out("Can not send %s %d\n",strerror(errno),errno); goto close_out; } dbg_out("write len :%d\n",write_len); wp += write_len; total_write += write_len; soc_remains -= write_len; } dbg_out("transfer %s %d/%d(%d)\n",path,total_write,size,file_remains); } rc=0; close_out: close(fd); if (rc<0) dbg_out("Can not send file:%s %s %d\n",path,strerror(errno),errno); return rc;}static intcreate_response(unsigned long type,const char *name,const size_t size,const char *dir,char **response){ int rc=0; char *buff=NULL; size_t act_len; gchar *res; size_t local_size; int msg_fid; char *local_name_p; dbg_out("here:\n"); if ( ( (!name) && (type != IPMSG_FILE_RETPARENT) ) || (!dir) || (!response) ) return -EINVAL; if (type != IPMSG_FILE_RETPARENT) dbg_out("file:%s size:%d(%x)\n", name,size,size); else dbg_out("Return to parent.\n"); switch(type) { case IPMSG_FILE_REGULAR: msg_fid=1; local_size=size; local_name_p=(char *)name; break; case IPMSG_FILE_DIR: msg_fid=2; local_size=0; local_name_p=(char *)name; break; case IPMSG_FILE_RETPARENT: msg_fid=3; local_size=0; local_name_p="."; break; default: dbg_out("Invalid type:%d\n",type); return -EINVAL; break; } /* *メッセージ形成 */ buff=g_malloc(IPMSG_BUFSIZ); if (!buff) return -ENOMEM; snprintf(buff,IPMSG_BUFSIZ-1,"xxxx:%s:%x:%d:", local_name_p,local_size,msg_fid); /* 仮の長さを算出 */ buff[IPMSG_BUFSIZ-1]='\0'; act_len=strlen(buff); snprintf(buff,IPMSG_BUFSIZ-1,"%04x:%s:%x:%d:", act_len,local_name_p,local_size,msg_fid); /* メッセージ作成 */ buff[IPMSG_BUFSIZ-1]='\0'; rc=-ENOSPC; if (act_len != strlen(buff)) { err_out("Message too long:%s\n",buff); goto error_out; } rc=convert_string_ipmsg_proto(buff,(const gchar **)&res); if (rc<0) { err_out("Can not convert code set:%s\n",buff); rc=-EINVAL; goto error_out; } *response=res; rc=0; error_out: if (buff) g_free(buff); return rc;}static intsend_header(tcp_con_t *con,const char *response){ int rc; size_t soc_remains; ssize_t send_len; char *wp; int buff_len; struct sigaction saved_act; if ( (!con) || (!response) ) return -EINVAL; soc_remains=strlen(response); if (wait_socket(con->soc,WAIT_FOR_WRITE,TCP_SELECT_SEC)<0) { err_out("Can not send socket\n"); goto error_out; } wp=(char *)response; dbg_out("Send:%s(%d, %x)\n",wp,soc_remains,soc_remains); while(soc_remains>0) { disable_pipe_signal(&saved_act); send_len=send(con->soc,wp,soc_remains,0); enable_pipe_signal(&saved_act); if (send_len<0) { if (errno == EINTR) continue; rc=-errno; err_out("Error:%s (%d)\n",strerror(errno),errno); goto error_out; } wp += send_len; soc_remains -= send_len; dbg_out("soc remains:%d\n",soc_remains); } rc=0; error_out: return rc; }static intread_directory_files(tcp_con_t *con,const char *parent,GnomeVFSFileInfo *info) { int rc; char *rel_path; char *full_path; char *res_message; if ( (!con) || (!parent) || (!info) ) return -EINVAL; if ( (!strcmp("..",info->name)) || (!strcmp(".",info->name) ) ) return -EINVAL; if (info->type==GNOME_VFS_FILE_TYPE_REGULAR) { rc=create_response(IPMSG_FILE_REGULAR,info->name,info->size,parent,&res_message); if (rc<0) return rc; dbg_out("Send file:%s\n",res_message); rc=send_header(con,res_message); g_free(res_message); if (rc<0) return rc; } rc=-ENOMEM; full_path=g_build_filename(parent,info->name,NULL); if (!full_path) return rc; /* send file */ tcp_transfer_file(con,full_path,info->size,0); g_free(full_path); return 0;}static intsend_directory(tcp_con_t *con,const char *top_dir,const char *basename,GnomeVFSFileInfo *info){ int rc; char *uri; GnomeVFSResult res; GnomeVFSDirectoryHandle *handle; char *next_dir; char *res_message; if ( (!top_dir) || (!info) || (!basename) ) return -EINVAL; rc=create_response(IPMSG_FILE_DIR,info->name,info->size,top_dir,&res_message); if (rc<0) return rc; dbg_out("Send dir:%s (%s)\n",res_message,top_dir); rc=send_header(con,res_message); g_free(res_message); if (rc<0) return rc; uri=gnome_vfs_get_uri_from_local_path(top_dir); if (!uri) return -ENOMEM; /* *ファイルを送付 */ res=gnome_vfs_directory_open(&handle,uri,GNOME_VFS_FILE_INFO_FOLLOW_LINKS); res=gnome_vfs_directory_read_next(handle,info); while (res==GNOME_VFS_OK) { read_directory_files(con,top_dir,info); res=gnome_vfs_directory_read_next(handle,info); } gnome_vfs_directory_close(handle); /* *ディレクトリを送付 */ res=gnome_vfs_directory_open(&handle,uri,GNOME_VFS_FILE_INFO_FOLLOW_LINKS); if (res!=GNOME_VFS_OK) { err_out("Can not open dir:%s %s (%d)\n", top_dir, gnome_vfs_result_to_string(res), res); goto error_out; } res=gnome_vfs_directory_read_next(handle,info); if (res!=GNOME_VFS_OK) { if (res != GNOME_VFS_ERROR_EOF) err_out("Can not read next dir:%s %s (%d)\n", top_dir, gnome_vfs_result_to_string(res), res); goto error_out; } while (res==GNOME_VFS_OK) { if ( (info->type==GNOME_VFS_FILE_TYPE_DIRECTORY) && ( (strcmp(info->name,"..")) && (strcmp(info->name,"."))) ){ dbg_out("dir:%s\n",info->name); next_dir=g_build_filename(top_dir,info->name,NULL); if (!next_dir) goto error_out; rc=send_directory(con,next_dir,info->name,info); g_free(next_dir); if (rc<0)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -